在 haskell 的新函数中使用过滤列表

Using a filtered list in a new function in haskell

所以我不太确定如何正确表达这个,但是说​​我想得到列表中所有奇数的总和,我有两个函数(sumList 和 getOddNumbers)并将它们组合成 sumOddList 还是有没有办法将这两个放在一个函数中?如果没有更好的功能,我该如何将它们组合成sumOddList?

getOddNumbers :: [Integer] -> [Integer]
getOddNumbers [] = []
getOddNumbers (x:xs)
    |odd x = x:getOddNumbers xs
    |otherwise = getOddNumbers xs

sumList :: [Integer] -> Integer
sumList list = case list of
   [] -> 0
   (x:xs) -> x + (sumList xs)

我之所以问,主要是因为将两个 diff 函数放在一起是我以前在使用 CodeWorld 放置颜色和形状以输出该颜色的形状时遇到的问题。

谢谢

(注意:我已经使用 Haskell 超过 5 个星期了,我显然是个菜鸟)

下面是函数oddSum :: [Integer] -> Integer的三种等价写法:

oddSum xs = sumList (getOddNumbers xs)

oddSum xs = sumList $ getOddNumbers xs

oddSum = sumList . getOddNumbers

顺便说一句,看看 Prelude 中的 filtersum 函数,您可以用它们分别替换 getOddNumberssumList

将输出作为输入传递给(另一个)函数

你基本上想要做的是使用getOddNumbers输出作为输入 用于 sumList 函数,所以我们可以定义一个 sumOddList 函数为:

sumOddList :: [Integer] -> Integer
sumOddList l = sumList (getOddNumbers l)

这里 l 是我们要处理的列表,因此结果是对 getOddNumbers l 的结果的函数应用(使用 sumList 函数)。

链接函数:(.)函数

上述模式很常见:我们经常希望先通过函数 g 传递数据,然后通过函数 f 传递结果。 Haskell 具有 (.) :: (b -> c) -> (a -> b) -> a -> c 功能到 "chain" 功能。因此,我们可以将 sumListgetOddNumbers 链接在一起,例如:

sumOddList :: [Integer] -> Integer
sumOddList = (.) sumList getOddNumbers

请注意,我们在这里不再使用 l 参数。 sumOddList 在这里定义为 "pipeline",其中数据首先传递给 getOddNumbers,然后由 sumList 函数传递 "post-processed"。

(.)函数也可以用作中缀运算符:

sumOddList :: [Integer] -> Integer
sumOddList = sumList . getOddNumbers

or is there a way to put these two together in a single function ... sumOddList?

是的。

通过使用一个人的输出作为另一个人的输入来链接函数,特别是在惰性评估下,但让我们依赖于编译器执行的融合。毕竟不能保证会发生(而且通常不会发生)。

相反,你说的 :

mapping f cons x xs = cons (f x) xs

filtering p cons x xs = if (p x) then (cons x xs) else xs

transduce xf cons z xs = foldr (xf cons) z xs

sumOddList xs = transduce (filtering odd) (+) 0 xs

因此,

> sumOddList [1..10]
25
> sum [1,3..10]
25
> transduce (mapping (+1) . filtering odd) (+) 0 [1..10]
35
> sum . filter odd . map (+1) $ [1..10]
35
> sum . map (+1) . filter odd $ [1..10]
30
> transduce (filtering odd . mapping (+1)) (+) 0 [1..10]
30

这是可行的,因为 folds fuse 通过组合它们的 reducer 函数的转换器(比如上面的 mappingfiltering 正在转换它们的 reducer 参数 cons):

foldr (+) 0
   . foldr (\x r -> x+1 : r) []
       . foldr (\x r -> if odd x then x : r else r) [] 
         $ [1..10]
=
foldr (+) 0
   . foldr ((\cons x r -> cons (x+1) r) (:)) []
       . foldr ((\cons x r -> if odd x then cons x r else r) (:)) [] 
         $ [1..10]
=
     foldr ((\cons x r -> cons (x+1) r) (+)) 0
       . foldr ((\cons x r -> if odd x then cons x r else r) (:)) [] 
         $ [1..10]
=
         foldr ((\cons x r -> if odd x then cons x r else r) 
                  ((\cons x r -> cons (x+1) r)   (+))) 0 
         $ [1..10]
=
         foldr ( ( (\cons x r -> if odd x then cons x r else r) 
                 . (\cons x r -> cons (x+1) r) ) (+))  0 
         $ [1..10]
=
         foldr ( (filtering odd . mapping (+1))  (+))  0 
         $ [1..10]
=
         foldr (  filtering odd ( mapping (+1)   (+))) 0 
         $ [1..10]
=
         30

一个foldr做三个的工作。 Fusion 显式实现,通过在cons操作从它们中抽象出来之后组合reducer函数,每个这样改变的函数成为一个cons转换器,因此,容易与其他此类 cons 转换函数 组合。