module Main where
rev :: [a] -> [a]
rev (x:[]) = x
rev (x:xs) = (rev xs):x
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
main = do
print (rev lst)
我正在通过99 Haskell Problems并尝试编写一个函数来反转列表(是的,我知道已有一个已经在前奏中)。
我的问题是,当我尝试编译上面的代码(或者只是将函数定义输入到GHCi中)时,我得到:
Occurs check: cannot construct the infinite type: a = [a]
In the expression: rev :: [a] -> [a]
In the definition of `it': it = rev :: [a] -> [a]
我不太确定我的类型在哪里出错以获得此错误。我猜它与我的模式匹配方式有关,但我不知道为什么。
答案 0 :(得分:17)
Travis对于特定错误是正确的,但是为了后来在搜索“无限类型错误”时发现此问题的任何人,这就是(看似神秘的)消息的含义:
在其签名中具有类型变量的函数意味着它不关心它在那里接收的类型 - 它不检查该类型的值,它们只是黑盒子。但是,当实际使用这样的函数时,类型变量将被固定为基于每次使用的更具体的东西。但是,不需要特定类型 - 类型变量也可以用其他类型变量填充。此统一过程是类型推断的一部分,并允许编译器将未知类型变量组合到程序的不同部分。
绑定类型变量时出现的错误最初通常看起来很神秘,特别是当GHC尝试在同一类型签名中组合变量时。例如:
如果编译器试图统一两个不同的变量,它会抱怨“由类型签名绑定的刚性类型变量”,这意味着它不能统一这两种类型,因为你明确告诉它们它们是不同的。
如果编译器尝试将类型变量与其自身的子集统一起来,例如确定类型变量a
应该与[a]
相同,那么它会抱怨无限类型,这只是意味着天真的统一说a
实际上[a]
实际上[[a]]
实际上是[[[a]]]
......等等。
答案 1 :(得分:9)
问题是(:)
的类型为a -> [a] -> [a]
,但您的第三行(rev (x:xs) = (rev xs):x
)需要它[a] -> a -> [a]
。
您想要的功能通常称为snoc
(即cons
的反义词,它是Lisp世界中(:)
的名称。它不是为Haskell标准库中的列表提供的,但您可以使用(++)
轻松完成相同的操作:
rev :: [a] -> [a]
rev (x:[]) = [x]
rev (x:xs) = rev xs ++ [x]
编辑:第二行也有问题,正如Landei在评论中指出的那样:你返回的是元素,而不是包含元素的列表。