Haskell 中的结构归纳

Structual induction in Haskell

谁能给我一个Haskell中的结构归纳的例子?我在网上找不到任何关于它的信息,有人给了我一个假设,但在制定基本案例时遇到了问题。

假设是: 对于 [a] 类型的所有列表 xsa 类型的所有 x 是:

toLast (x:xs) = xs |++| [x]

|++| 是我自己的连接两个列表的版本,toLast 是列表的 header 到列表末尾的函数。我试图自己解决这个问题并得到 toLast [] = [] |++| [] 但我不确定这是否正确。

Can anyone give me an example of Structural induction in Haskell?

结构归纳总是需要两个步骤:

  1. 考虑基本情况
  2. 通过假设列表 xs 存在函数体来考虑一般情况,并使用该假设为下一步构建定义 (x :xs)。这就是所谓的归纳步骤

让我们使用结构归纳的思想来定义您的 |++| 函数,在我看来这是一个更好的例子。

|++| 接受两个列表并输出一个列表,该列表是第一个列表与第二个列表的串联,因此类型签名为:

(|++|) :: [a] -> [a] -> [a]

第二个列表输入永远不变,所以我们说第一个列表是递归的参数。因此,基本情况是第一个列表为空时:

(|++|) [] ys = ys

现在,让我们考虑 |++| 的第一个参数不是空列表而是 xs 的情况。归纳步骤是假设我们的函数 (|++|) xs ys 有效(因为它在基本情况下被证明是有效的)并使用该假设来定义 |++| 的第一个输入是 (x:xs)。将这些放在一起,到目前为止,我们有:

(|++|) []     ys = ys -- base case
(|++|) (x:xs) ys = let assumedAlreadyConcatenatedList = ((|++|) xs ys) in *something...* assumedAlreadyConcatenatedList -- half-done general case

假设 ((|++|) xs ys) 工作正常,我们只需要定义要对 x 做什么,然后我们就完成了。我们如何将 x 连接到已连接项目的列表中?我们使用缺点:

(|++|) []     ys = ys -- base case
(|++|) (x:xs) ys = let assumedAlreadyConcatenatedList = ((|++|) xs ys) in x : assumedAlreadyConcatenatedList -- completed general case.

希望很明显,我们总是需要一个基本案例来支持我们在归纳步骤中的假设。