无法将预期类型“[a]”与实际类型“a”匹配

时间:2017-10-24 14:10:59

标签: list haskell types list-comprehension

我有以下功能,它应该将给定列表中的所有数字相加到当前位置。例如,subtotal [1, 2, 3, 4] = [1, 3, 6, 10],因为1 = 1,1 + 2 = 3,1 + 2 + 3 = 6和1 + 2 + 3 + 4 = 10.

这是我的代码:

subtotal :: Num a => [a] -> [a]
subtotal [] = []
subtotal xs = [y | n <- [1..length xs], y <- sum(take n xs)]

问题是我得到了这个错误:

cw.hs:3:46: error:
    * Couldn't match expected type `[a]' with actual type `a'
      `a' is a rigid type variable bound by
        the type signature for:
          subtotal :: forall a. Num a => [a] -> [a]
        at cw.hs:1:1-31
    * In the expression: sum (take n xs)
      In a stmt of a list comprehension: y <- sum (take n xs)
      In the expression:
        [y | n <- [1 .. length xs], y <- sum (take n xs)]
    * Relevant bindings include
        xs :: [a] (bound at cw.hs:3:10)
        subtotal :: [a] -> [a] (bound at cw.hs:2:1)
  |
3 | subtotal xs = [y | n <- [1..length xs], y <- sum(take n xs)]
  |                                              ^^

我该如何解决?

2 个答案:

答案 0 :(得分:7)

sum(take n xs) 不是列表,因此您无法对其进行迭代。为了将表达式的结果添加到列表中,您将表达式放在列表推导的头部

subtotal :: Num a => [a] -> [a]
subtotal xs = [sum (take n xs) | n <- [1..length xs]]

但你在这里使用lengthlength有点危险,因为列表可以是无限的,然后你的函数将简单地保持循环,并且永远不会返回一个元素。但是,您可以使用inits来获取所有列表:

Prelude Data.List> inits [1,4,2,5]
[[],[1],[1,4],[1,4,2],[1,4,2,5]]

所以你可以使用:

import Data.List(inits)

subtotal :: Num a => [a] -> [a]
subtotal xs = [sum sub | sub <- tail (inits xs)]

但这仍然不是很有效:现在我们计算每个子列表的总和。但这里的一个问题是我们分别计算每个列表的总和。这很奇怪,因为 i -th结果的总和只是 i-1 -th结果加上 i -th的总和xs的元素。我们可以使用scanl1 :: (a -> a -> a) -> [a] -> [a]

subtotal :: Num a => [a] -> [a]
subtotal xs = scanl1 (+) xs

甚至更简单优雅:

subtotal :: Num a => [a] -> [a]
subtotal = scanl1 (+)

答案 1 :(得分:4)

在列表推导中,语句y <- ys表示ys是一个列表,y遍历该列表的元素。因此y <- sum (take n xs)表示sum生成一个列表,您迭代该列表。但sum只生成一个数字,而不是列表;所以你得到一个错误。

您希望使用let代替<-来分配简单表达式:

subtotal xs = [y | n <- [1..length xs], let y = sum(take n xs)]

或者只是将表达式直接放入理解的头部:

subtotal xs = [sum (take n xs) | n <- [1..length xs]]

PS:你的第一个案例(对于空列表)是多余的。这只是第二种情况的一个特例。