【问题标题】:Using a filtered list in a new function in haskell在haskell的新函数中使用过滤列表
【发布时间】:2019-02-01 16:19:31
【问题描述】:

所以我不太确定如何正确表达这一点,但是说我想得到一个列表中所有奇数的总和,我是否有两个函数(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 周了,显然我完全是个菜鸟)

【问题讨论】:

    标签: list function haskell recursion composition


    【解决方案1】:

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

    oddSum xs = sumList (getOddNumbers xs)
    
    oddSum xs = sumList $ getOddNumbers xs
    
    oddSum = sumList . getOddNumbers
    

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      链接函数:(.) 函数

      上述模式很常见:我们经常希望首先通过函数g 传递数据,然后通过函数f 传递结果。 Haskell 有 (.) :: (b -> c) -> (a -> b) -> a -> c 函数来“链接”函数。因此,我们可以将 sumListgetOddNumbers 链接在一起,如下所示:

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

      请注意,我们在这里不再使用l 参数。 sumOddList 在这里定义为“管道”,其中数据首先传递给getOddNumbers,然后由sumList 函数进行“后处理”。

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

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

      【讨论】:

        【解决方案3】:

        或者有没有办法将这两者放在一个函数中...sumOddList

        是的。

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

        相反,你所说的 :

        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 通过组合它们的 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转换器,因此,易于组合 em> 与其他类似的cons-转换函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-27
          • 1970-01-01
          • 2018-07-22
          相关资源
          最近更新 更多