87

我是 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 中“无限类型”错误的一般准则:

更正的代码

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

问题是什么:

我的类型签名声明 intersperse 的第二个参数是列表的列表。因此,当我对“s (x:y:xs)”进行模式匹配时,x 和 y 变成了 lists。然而我将 x 和 y 视为元素,而不是列表。

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

大多数时候,当您遇到此错误时,您已经忘记了您正在处理的各种变量的类型,并且您试图使用一个变量,就好像它是其他类型一样。仔细查看所有内容的类型与您使用它的方式,这通常会发现问题。

4

4 回答 4

38

问题出在最后一个子句中,您将 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 是一个无限嵌套的列表。这是不允许的(无论如何,这不是你的意思)。

编辑:上面的代码中还有另一个错误。它应该是:

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) = x ++ [s] ++ intersperse s xs
于 2009-04-27T21:32:37.107 回答
7

通常添加显式类型定义可以使编译器的类型错误消息更有意义。但是在这种情况下,显式类型会使编译器的错误消息变得更糟。

看看当我让 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'

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

于 2011-03-22T23:53:11.820 回答
3

我可能是错的,但似乎你正在尝试解决一个更困难的问题。您的版本intersperse不仅将值与数组散布,而且还将其展平一层。

Haskell 中的List模块实际上提供了一个 intersperse 函数。它在列表中的每个元素之间放入给定的值。例如:

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 时希望我们做的。当然,我可以完全出局。

于 2009-04-27T21:34:24.153 回答
1

我还发现解释了错误的含义。

每次解释器/编译器给我这个错误都是因为我使用了一些类型参数化的元组作为形式参数。通过删除包含类型变量的函数的类型定义,一切正常。

我仍然无法弄清楚如何修复它并保留函数类型定义。

于 2010-05-27T13:36:29.830 回答