Haskell 错误;发生检查:无法构造无限类型:t ~ [t]

Haskell Error; Occurs check: cannot construct the infinite type: t ~ [t]

我昨天问了几个问题,越来越多的问题不断出现在我的代码中。

我有一个名为 sub 的函数。 Sub 接受一个数字并输出一个数字列表,代码如下。

sub 5 =  [1]
sub x =
    do 
        xs <- sub (x - 1)
        (x:xs)  

我曾经不得不在最上面一行有 sub 5 = return [1] 的地方,在最下面一行,return (x:xs)。昨天有人回答说把这些去掉,因为它把一个列表放在一个列表中,就像 [[int]] 一样。如果我取出 returns 这会产生一个错误(在问题标题中),我真的无法理解这个问题。

只是想知道是否有人能理解它,

谢谢

让我们重写您必须做的事情,以便更清楚地说明为什么这不会进行类型检查。我们首先将 do 符号脱糖得到

sub :: Int -> [Int]
sub 5 = [1]
sub x = sub (x-1) >>= \xs -> (x:xs)

现在回想一下如何为列表定义 >>=ys >>= f = concat (map f ys)。这里 f\xs -> (x:xs)yssub (x-1),因此我们有:

sub :: Int -> [Int]
sub 5 = [1]
sub x = concat (map (\xs -> (x:xs)) (sub (x-1)))

sub (x-1) 的类型是 [Int],因此 map 的第一个参数必须是接受 Int 的函数。它不是 - 它需要一个列表!

正如你所说,你曾经有sub 5 = return [1]。回想一下,对于列表 return y = [y],那么在那种情况下,您的 sub 将具有签名 Int -> [[Int]]。现在上面的 sub (x-1) 将是列表的列表,而 map 的第一个参数应该是一个接受 lists 的函数,事实确实如此。所以事情经过了类型检查。

一条建议:给你的顶级定义显式签名(你想要 sub :: Int -> [Int] 还是 sub :: Int -> [[Int]]?)!它会让你更容易理解正在发生的事情,因为它会迫使你思考你真正想要的是什么。

我将尝试扩展错误的含义。

让 desugar 做符号 (details):

sub 5 =  [1]
sub x =
        sub (x - 1) >>= \xs ->
        (x:xs)  

>>= 运算符具有下一个类型(参见 here):

(>>=) :: Monad m => m a -> (a -> m b) -> m b

它的第一个参数 sub (x - 1) 的类型为 [Int],因此我们可以将类型变量 m 实例化为 [] 并将 a 实例化为 Int:

(>>=) :: [Int] -> (Int -> [b]) -> [b]

(注意[a]是列表类型的特殊语法,可以读成[] a)

所以第二个参数 \xs -> (x:xs) 的类型应该是 Int -> [b]。现在应该清楚 xs 的类型是 Int,而不是您所期望的 [Int]

现在让我们考虑 :。它的类型是 c -> [c] -> [c]。让我们写下所有约束:

(:)     :: c -> [c] -> [c]
x       :: Int
xs      :: Int
x : xs  :: [Int]

他们不能同时满足,因为他们要求 c[c] 都是 Int.