haskell函数,用于对列表的数字求和

时间:2016-10-12 04:39:04

标签: haskell

我试图做一个给定操作符和函数的函数将通过这样的列表:

reduce (*) even [1,2,3,4,5] => 8
reduce (+) odd [1,2,3,4,5]  => 9

起初我有这样的事情:

reduce :: (Int-> Int-> Int) -> (Int->Bool) -> [Int] -> Int
reduce op x y = foldl op 1 (filter x y)

它适用于乘法,但在尝试总和时添加了一个数字。所以我想添加一个if:

reduce :: (Int-> Int-> Int) -> (Int->Bool) -> [Int] -> Int
reduce op x y = 
    if op == (*) then foldl op 1 (filter x y)
        else if op == (+) then foldl op 0 (filter x y)
            else 0

然而,当我这样做时,我收到以下错误:

定义reduce

所需的Eq(Int - > Int - > Int)实例

这究竟是什么意思?有任何想法吗?提前致谢

2 个答案:

答案 0 :(得分:4)

这意味着使用当前的导入,您无法比较函数的相等性(即使使用合适的导入,也没有很好的方法来实现您要求的相等性。)

一个简单的解决方案是要求用户提供操作和单元,因此:

reduce op u x y = foldl op u (filter x y)

在许多感兴趣的情况下,已经有一个Monoid实例指定了运算符和单元。例如,有SumProduct个实例,因此您可以考虑编写

reduce inject p = foldMap inject . filter p

将像这样使用:

> reduce Sum even [1..5]
Sum {getSum = 6}
> reduce Product odd [1..5]
Product {getProduct = 15}

答案 1 :(得分:3)

  

这究竟是什么意思?有任何想法吗?提前致谢

您正在尝试将某些(Int -> Int -> Int)与另一个进行比较。但是函数无法在相等性上进行检查。改为提供初始值:

reduce :: (Int -> Int -> Int) -> (Int -> Bool) -> Int -> [Int] -> Int
reduce op f x xs = foldl op x (filter f xs)

顺便说一句,您可以概括函数的类型:

reduce :: (b -> a -> b) -> (a -> Bool) -> b -> [a] -> a
reduce op f x xs = foldl op x (filter f xs)

或者,使用幺半群和foldMap