我试图在haskell中获得无限的斐波纳契数列表,但以下代码无法编译:
fib1 x = fib1 (x : (last $ init x) + (last x))
result1 = fib1 [1,2]
我最终使用了这段代码:
fib2 x y = head y : fib2 y (zipWith (+) x y)
result2 = fib2 [0,1] [1,1]
但是,我不明白为什么第一个代码片段没有编译。错误如下。我只是在寻找一个答案,为什么第一个没有编译,但第二个没有。
p2.hs:3:16:
Occurs check: cannot construct the infinite type: a0 = [a0]
In the first argument of `(:)', namely `x'
In the first argument of `fib1', namely
`(x : (last $ init x) + (last x))'
In the expression: fib1 (x : (last $ init x) + (last x))
p2.hs:3:21:
Occurs check: cannot construct the infinite type: a0 = [a0]
In the first argument of `(+)', namely `(last $ init x)'
In the second argument of `(:)', namely
`(last $ init x) + (last x)'
In the first argument of `fib1', namely
`(x : (last $ init x) + (last x))'
p2.hs:3:44:
Occurs check: cannot construct the infinite type: a0 = [a0]
Expected type: [[a0]]
Actual type: [a0]
In the first argument of `last', namely `x'
In the second argument of `(+)', namely `(last x)'
In the second argument of `(:)', namely
`(last $ init x) + (last x)' Failed, modules loaded: none.
答案 0 :(得分:4)
第一个代码示例的问题是您无法为其编写类型注释。这将是无限的。让我们试试吧:
fib1 x = fib1 (x : (last $ init x) + (last x))
首先让我们对其进行简化,因为我们可以在没有last
和init
内容的情况下复制相同的问题:
fib1 x = fib1 (x : undefined)
fib1
的论点是什么类型。在左侧,我们只看到x
,但没有关于它的更多信息。我们可以假设它有一些类型a
。在右侧,我们尝试使用参数调用函数,该参数必须是列表(因为它由:
运算符构造)。列表元素以x
开头,其类型为a
。因此,此处fib1
的参数类型为[a]
。由于我们无法使用两种不同类型的参数调用函数,因此即使在左侧x
,也必须具有类型[a]
。但这迫使我们将严谨方面的类型更新为[[a]]
。然后再在左边。此过程永远不会停止,类型会增长和增长,因为无法将a
与[a]
统一起来。因此表达式没有有效类型,GHC会拒绝它。
另一方面,第二个片段没有问题。
fib2 x y = head y : fib2 y (zipWith (+) x y)
我们可以轻松地向GHCi询问此功能的类型,并乐意回答我们:
Prelude> let fib2 x y = head y : fib2 y (zipWith (+) x y)
Prelude> :t fib2
fib2 :: Num a => [a] -> [a] -> [a]
这种类型是完全有限的。