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

bksxznpy  于 2023-02-13  发布在  其他
关注(0)|答案(4)|浏览(120)

我是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.

在阅读了几个答案并进一步研究后更新(仅供参考,这是在最近的编辑中被某人意外删除的):

以下是一些更正的代码以及处理Haskell中"infinite type"错误的一般准则:

更正代码
intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) =  x ++ s:intersperse s xs
问题是什么:

我的类型签名声明第二个要插入的参数是列表的列表,因此,当我对"s(x:y:xs)"进行模式匹配时,x和y变成了列表,但我把x和y当作元素,而不是列表。

处理"无限类型"错误的准则:

大多数情况下,当你遇到这个错误时,你已经忘记了你正在处理的各种变量的类型,并且你试图使用一个变量,就好像它是其他类型的一样。仔细看看每件事是什么类型的,以及你是如何使用它的,这通常会发现问题。

but5z9lq

but5z9lq1#

问题出在最后一个子句中,你把x和y当作元素,而它们是列表。

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

发生无限类型错误的原因是:一个运算符的类型是a -〉[a] -〉[a],而你把它当作[a] -〉a -〉[a],这意味着[a]必须与a标识,这意味着a是一个无限嵌套的列表,这是不允许的(而且也不是你想要的)。

**编辑:**上面的代码还有一个bug,应该是:

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

qfe3c7zg2#

通常,添加显式类型定义可以使编译器的类型错误信息更有意义,但在这种情况下,显式类型定义会使编译器的错误信息更糟糕。
看看当我让ghc猜测插入类型时会发生什么:

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'

这清楚地指出了代码中的bug,使用这种技术,你不必像其他人建议的那样盯着所有的东西,仔细考虑类型。

omhiaaxx

omhiaaxx3#

也许我错了,但看起来你在试图解决一个更困难的问题,你的intersperse版本不仅将值分散在数组中,而且还将其扁平化了一层。
Haskell中的List模块实际上提供了一个sperse函数,它把给定的值放在列表中的 every 元素之间,例如:

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"]

我猜这就是你想做的,因为这是我学 haskell 时,我的教授想让我们做的,当然,我可以完全不去.

uhry853o

uhry853o4#

我还找到了this,它解释了错误的含义。
每次解释器/编译器给我这个错误,都是因为我使用了一些类型参数化的元组作为形参,通过删除函数的类型定义,所有的工作都是正确的,它包含类型变量。
我仍然想不出如何既修复它又保留函数类型定义。

相关问题