Haskell 发生检查:无法构造无限类型:t~[t]
我开始学习哈斯克尔。我正在试着运行这个代码Haskell 发生检查:无法构造无限类型:t~[t],haskell,Haskell,我开始学习哈斯克尔。我正在试着运行这个代码 -- Helpers.hs module Helpers where lst1 +++ lst2 = if null lst1 then lst2 else (head lst1) : (tail lst1 +++ lst2) reverse2 lst = if null lst then [] else reverse2 (tail lst) : (he
-- Helpers.hs
module Helpers
where
lst1 +++ lst2 = if null lst1
then lst2
else (head lst1) : (tail lst1 +++ lst2)
reverse2 lst = if null lst
then []
else reverse2 (tail lst) : (head lst)
我发现这个错误:
D:\Haskell\project>cabal configure
Resolving dependencies...
Configuring one-0.1.0.0...
D:\Haskell\project>cabal build
Building one-0.1.0.0...
Preprocessing executable 'one' for one-0.1.0.0...
[1 of 2] Compiling Helpers ( src\Utils\Helpers.hs, dist\build\one\one-t
mp\Helpers.o )
src\Utils\Helpers.hs:11:21:
Occurs check: cannot construct the infinite type: t ~ [t]
Relevant bindings include
lst :: [[t]] (bound at src\Utils\Helpers.hs:9:10)
reverse2 :: [[t]] -> [t] (bound at src\Utils\Helpers.hs:9:1)
In the first argument of `(:)', namely `reverse2 (tail lst)'
In the expression: reverse2 (tail lst) : (head lst)
如何修复它?反向2(尾部lst)类型为[a]
,而头部lst
类型为a
。同时,:
运算符的类型为a->[a]->[a]
。当您尝试执行reverse2(tail-lst):(head-lst)
时,Haskell认为head-lst
是一个列表,其元素的类型与reverse2(tail-lst)
相同,即head-lst:[[a]]
。然而,head lst
也必须与reverse2(tail lst)
的元素类型相同,这意味着reverse2(tail lst):[[a]]]
,但是head lst
必须是[[[a]]]]
,然后reverse2(tail lst)
必须是[a]]]]]
,,我想你能看到这是怎么回事
发生此问题的原因是您使用的
:
不正确。如果要将元素附加到列表中,最简单的方法是reverse2(tail lst)+[head lst]
正如jwodder所写内容的扩展说明一样,如果显式键入内容,则可以得到更有用的错误消息:
Prelude> let reverse2 :: [a] -> [a]; reverse2 lst = if null lst then [] else (reverse2 (tail lst)) : (head lst)
<interactive>:6:70:
Couldn't match expected type ‘a’ with actual type ‘[a]’
‘a’ is a rigid type variable bound by
the type signature for reverse2 :: [a] -> [a] at <interactive>:6:17
Relevant bindings include
lst :: [a] (bound at <interactive>:6:38)
reverse2 :: [a] -> [a] (bound at <interactive>:6:29)
In the first argument of ‘(:)’, namely ‘(reverse2 (tail lst))’
In the expression: (reverse2 (tail lst)) : (head lst)
Prelude>let reverse2::[a]->[a];reverse2 lst=如果lst为空,则[]否则(reverse2(尾部lst)):(头部lst)
:6:70:
无法将预期类型“a”与实际类型“[a]”匹配
“a”是一个刚性类型变量,由
reverse2::[a]->[a]at:6:17的类型签名
相关绑定包括
lst::[a](于6:38绑定)
背面2::[a]->[a](于6:29绑定)
在“(:)”的第一个参数中,即“(reverse2(tail lst))”
在表达式中:(反转2(尾部lst)):(头部lst)
因此,当前的问题是,您将错误类型的参数传递给了:
运算符,haskell试图使它们成为正确的类型,而它努力使它们成为正确的类型会导致错误消息变得模糊
作为一般策略,当像这样出现奇怪的错误消息时,我开始将类型签名应用于它抱怨的内容,这样haskell就不会试图推断出与我的意图相去甚远的类型签名
使用您的代码执行此操作时,我首先将其添加到reverse2
:
reverse2 :: [t] -> [t]
reverse2 lst = if null lst
then []
else reverse2 (tail lst) : (head lst)
这会将错误消息更改为:
Couldn't match expected type ‘t’ with actual type ‘[t]’
‘t’ is a rigid type variable bound by
the type signature for reverse2 :: [t] -> [t]
at /tmp/flycheck-stackov.hs:6:13
Relevant bindings include
lst :: [t] (bound at /tmp/flycheck-stackov.hs:7:10)
reverse2 :: [t] -> [t] (bound at /tmp/flycheck-stackov.hs:7:1)
In the first argument of ‘(:)’, namely ‘reverse2 (tail lst)’
In the expression: reverse2 (tail lst) : (head lst)
好的,现在它说“当查看:
的第一个参数时,我期望类型t
,但得到类型[t]
”
事实上,如果我们问ghci的类型是什么,我们会看到:
Prelude> :t (:)
(:) :: a -> [a] -> [a]
因此,:
的左参数必须是单个项,右参数必须是列表。您正在使用左侧的列表,右侧的单个项目
要按照您想要的方式连接,正如另一个答案所说,您应该使用++
:
reverse2 :: [t] -> [t]
reverse2 lst = if null lst
then []
else reverse2 (tail lst) ++ [head lst]
(另外,您的
main
例程中有一个类型错误。您想说putStrLn$reverse2[2,8,7]
而不是putStrLn.reverse2[2,8,7]
)您应该能够通过以下方式修复它:
reverse2 lst = if null lst
then []
else reverse2 (tail lst) ++ [head lst]
@jwodder已经解释了这不起作用的更多理论原因
注意,上面的实现效率很低,因为++
完全遍历它的第一个参数,然后进行连接
下面是一个更复杂的方法
reverse3 lst =
let aux lst acc = if null lst then acc else aux (tail lst) (head lst : acc)
in aux lst []
显式注释类型通常很有帮助(例如,您编写的
reverse2::[a]->[a]
,因为您什么时候能够使用类型的列表[[a][[a][[a][[a][a][a][a][a][a][a][a][a][a]了?这就是类型a][a]你也在描述,它是非常单元格和错误倾向的,在样式上使用NULL。模式匹配是非常优越的。我认为这确实是正确的答案,但是我会考虑添加解释“JWODDER给出的”这样的答案可以更完整。我也建议添加模式匹配策略作为一种替代。code>if..then..else
(不删除该实现),因为它是此类函数的更标准定义。
reverse3 lst =
let aux lst acc = if null lst then acc else aux (tail lst) (head lst : acc)
in aux lst []