使用递归键入错误

时间:2016-08-22 14:39:43

标签: list haskell recursion types type-mismatch

我想从列表中选择每两个元素来创建一个新列表,然后我得到这样的错误:

test.hs:4:20: error:
? Couldn't match expected type ‘[a]’ with actual type ‘a’
  ‘a’ is a rigid type variable bound by
    the type signature for:
      test :: forall a. [a] -> [[a]]
    at test.hs:1:7
? In the expression: x1
  In the expression: [x1]
  In a case alternative: [x1] -> [x1]
? Relevant bindings include
    x1 :: a (bound at test.hs:4:6)
    list :: [a] (bound at test.hs:2:6)
    test :: [a] -> [[a]] (bound at test.hs:2:1)

这是我的代码:

test::[a]->[[a]]
test list = case list of
    []          ->[]
    [x1]        ->[x1]
    [x1,x2]     ->[x1,x2]
    x1:x2:xs    ->[[x1,x2],(test xs)]

任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:2)

在Haskell中通常首选编写函数的不同子句 - 这与case的作用相同,但通常更易读。另外,请不要将您的函数命名为test

更像这样:

chunksÀ2 :: [a] -> [[a]]
chunksÀ2 [] = []
chunksÀ2 [x1] = [x1]
chunksÀ2 [x1,x2] = [x1,x2]
chunksÀ2 (x1:x2:xs) = [[x1,x2], chunksÀ2 xs]

现在,这些条款中的每一个都必须独立地进行类型检查。我将从第二个开始:

chunksÀ2 [x1] = [x1]

嗯。签名表示结果应该是嵌套列表,输入是简单列表。当然,你的意思是:

chunksÀ2 [x1] = [[x1]]

这是一个列表,其唯一元素是包含一个元素的列表。

类似于下一个条款:

chunksÀ2 [x1,x2] = [[x1,x2]]

请注意

chunksÀ2 [x1,x2] = [[x1],[x2]]

也是可能的。 (练习:为什么这不是你想要的?)

令人感兴趣的地方在recursive子句中。您已使用匹配x1:x2:xs的模式正确地从输入列表中弹出前两个元素。现在你需要重新组装它们。 [x1,x2]正好在结果列表的第一个元素,但是呢? chunksÀ2 xs的类型为[[a]],因此,如果您将其放入另一个[],则您的类型为[[[a]]]。这显然太多了!

相反,您只想 [x1,x2]添加到chunksÀ2 xs。好吧,使用cons运算符,你也用于模式匹配:

chunksÀ2 (x1:x2:xs) = [x1,x2] : chunksÀ2 xs

最后,空子句。这实际上就像你写的一样,但你知道为什么吗?请注意,[]可以包含您喜欢的任何列表类型:

Prelude> [] :: [Int]
[]
Prelude> [] :: [String]
[]
Prelude> [] :: [[(Double,[Maybe Bool])]]
[]

chunksÀ2 [] = []

你真的有

chunksÀ2 ([] :: [a]) = [] :: [[a]]

你也可以写

chunksÀ2 [] = [[]]

但这不会做正确的事。

答案 1 :(得分:1)

[][x1][x1, x2][[x1, x2], (test xs)]都必须具有相同类型,才能成为同一功能的可能值。我认为你在第二种情况下需要[[x1]]而在第三种情况下需要[[x1, x2]],因为在这两种情况下,只有一个长度最多只有一个。请注意,您甚至不需要第三种情况,因为xs = []的第四种情况涵盖了第三种情况。您也可以通过导入Data.List.Split并使用其chunksOf 2来跳过实现此功能。