我试图找到列表中所有内容的平方和,例如:
[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
有人能帮助我吗?
答案 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
。