为什么 Haskell 代码会产生“无限类型”错误?

我是 Haskell 的新手,面临着一个“无法构造无限类型”的错误,我无法理解。

事实上,除此之外,我还没能找到一个很好的解释,这个错误甚至意味着什么,所以如果你能超越我的基本问题,并解释“无限类型”错误,我真的很感激。

密码是这样的:

intersperse :: a -> [[a]] -> [a]


-- intersperse '*' ["foo","bar","baz","quux"]
--  should produce the following:
--  "foo*bar*baz*quux"


-- intersperse -99 [ [1,2,3],[4,5,6],[7,8,9]]
--  should produce the following:
--  [1,2,3,-99,4,5,6,-99,7,8,9]


intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:y:xs) = x:s:y:intersperse s xs

试图将其加载到解释器中的错误如下:

Prelude> :load ./chapter.3.ending.real.world.haskell.exercises.hs
[1 of 1] Compiling Main (chapter.3.ending.real.world.haskell.exercises.hs, interpreted )


chapter.3.ending.real.world.haskell.exercises.hs:147:0:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `intersperse'
Failed, modules loaded: none.

谢谢。

--

以下是一些更正的代码和处理哈斯克尔“无限类型”错误的一般指南:

更正代码

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) =  x ++ s:intersperse s xs

问题是:

我的类型签名声明第二个要散布的参数是 名单。因此,当我的模式与“ s (x: y: xs)”匹配时,x 和 y 就变成了 清单。但是我把 x 和 y 看作元素,而不是列表。

处理“无限类型”错误的指南:

大多数情况下,当您得到这个错误时,您已经忘记了正在处理的各种变量的类型,并且您试图使用一个变量,就好像它是其他类型一样。仔细观察每样东西的类型和使用方式,这通常会发现问题。

45170 次浏览

The problem is in the last clause, where you treat x and y as elements, while they are lists. This will work:

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:y:xs) = x ++ [s] ++ y ++ intersperse s xs

The infinite type error occurs because the : operator has type a -> [a] -> [a], while you treat it as [a] -> a -> [a], which means that [a] must be identified with a, which would mean that a is an infinitely nested list. That is not allowed (and not what you mean, anyway).

Edit: there is also another bug in the above code. It should be:

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) = x ++ [s] ++ intersperse s xs

I may be wrong, but it seems you're trying to solve a more difficult problem. Your version of intersperse doesn't just intersperse the value with the array, but also flattens it one level.

The List module in Haskell actually provides an intersperse function. It puts in the value given between every element in the list. For example:

intersperse 11 [1, 3, 5, 7, 9] = [1, 11, 3, 11, 5, 11, 7, 11, 9]
intersperse "*" ["foo","bar","baz","quux"] = ["foo", "*", "bar", "*", "baz", "*", "quux"]

I'm assuming this is what you want to do because it's what my professor wanted us to do when I was learning Haskell. I could, of course, be totally out.

Also I found this which explains the meaning of the error.

Every time the interpreter/compiler gives me this error it's because I'm using some type-parametrized tuple as formal parameter. Everything works correctly by removing the type definition of the function, which was containing type variables.

I still cannot figure out how to both fix it and keep the function type definition.

Often adding an explicit type definition can make the compiler's type error message make more sense. But in this case, the explicit typing makes the compiler's error message worse.

Look what happens when I let ghc guess the type of intersperse:

Occurs check: cannot construct the infinite type: a = [a]
Expected type: [a] -> [[a]] -> [[a]]
Inferred type: [a] -> [[a]] -> [a]
In the second argument of `(:)', namely `intersperse s xs'
In the second argument of `(:)', namely `y : intersperse s xs'

That clearly points toward the bug in the code. Using this technique you don't have to stare at everything and think hard about the types, as others have suggested doing.