Haskell - 将所有内容都放在列表中

时间:2015-03-05 22:58:50

标签: haskell

我试图找到列表中所有内容的平方和,例如:

[1,2,3] --> 1+4+9 --> 14

这是我的尝试:

sqSum :: (a->a)->[a]->a
sqSum _ [] = 0
sqSum f (x:xs) = f x + sqSum f xs

square :: Int->Int
square num = num*num

我这样使用它......

sqSum square [1,2,3]

但是我收到了一个错误:

square.hs:2:14:
    No instance for (Num a) arising from the literal `0'
    Possible fix:
      add (Num a) to the context of
        the type signature for sqSum :: (a -> a) -> [a] -> a
    In the expression: 0
    In an equation for `sqSum': sqSum _ [] = 0

有人能帮助我吗?

1 个答案:

答案 0 :(得分:9)

问题在于,您说sqSum的类型是(a->a)->[a]->a,换句话说,它可以对任何类型的数据进行操作。

然后你继续说空列表给出0的结果。当类型是数字时,这是有效的,但是当类型是字符串,元组或函数时,这是有效的。

您可以通过在类型签名中添加类约束来指定您的函数仅适用于数字:

sqSum :: Num a => (a->a)->[a]->a
sqSum _ [] = 0
sqSum f (x:xs) = f x + sqSum f xs

square :: Int->Int
square num = num*num

您还可以通过将输入类型与输出类型分离,并说您可以接受任何类型的列表,只要您具有将其转换为要求和的数字的函数,就可以更进一步:

sqSum :: Num b => (a -> b) -> [a] -> b

现在,您可以同时执行sqSum square [1,2,3]sqSum length ["a", "be", "sea"]

哦,而不是硬编码+0,你可以传入一个组合函数和一个零值:

sqSum :: (a -> b -> b) -> b -> [a] -> b
sqSum _ zero [] = zero
sqSum f zero (a:rest) a `f` sqSum f zero rest

现在你可以从零开始并使用

添加所有方块
sqSum ((+) . square) 0 [1,2,3]

或者从1开始,然后使用

将所有方块相乘
sqSum ((*) . square) 1 [1,2,3]

或者从空字符串开始并使用

连接所有数字
sqSum ((++) . show) "" [1,2,3]

此版本的sqSum已存在于标准库中,名为foldr