【问题标题】:Understanding function which implements foldr and foldl了解实现 foldr 和 foldl 的函数
【发布时间】:2021-06-05 20:55:16
【问题描述】:

在某些情况下,我不明白foldrfoldl 在函数中是如何使用的。

这里有几个例子,然后我解释为什么我不理解它们:

-- Two implementation of filter and map
map' f = foldr (\x acc -> (f x):acc) [] 
map'' f xs = foldl (\acc x -> acc ++ [(f x)]) [] xs 

filter' f xs = foldr(\x acc -> if(f x) then x:acc else acc) [] xs 
filter'' f  = foldl(\acc x -> if(f x) then acc++[x] else acc) [] 

为什么map'' 使用xs 而不是map'map' 不应该也需要列表理解公式的列表吗?

filter'filter'' 的情况相同。

这是一个按排序顺序插入元素的实现:

insert e [] = [e]
insert e (x:xs)
     | e > x = x: insert e xs
     | otherwise = e:x:xs
sortInsertion xs = foldr insert [] xs
sortInsertion'' xs = foldl (flip insert) [] xs

为什么insert的参数在sortInsertion([] xs)(空列表和列表)中与insert(e [])的定义(元素和空列表)相比,会翻转

【问题讨论】:

    标签: list haskell fold function-definition


    【解决方案1】:

    为什么map'' 使用xs 而不是map'map' 不应该也需要列表理解公式的列表吗? filter'filter'' 的情况相同。

    这称为“eta-reduction”,它是一种省略冗余参数名称的常用方法(“无点样式”)。本质上,只要你有一个函数,它的主体只是一个函数对其参数的应用,你就可以减少参数:

    add :: Int -> Int -> Int
    add x y = x + y
    
    -- “To add x and y, call (+) on x and y.”
    add :: (Int) -> (Int) -> (Int)
    add x y = ((+) x) y
    
    -- “To add x, call (+) on x.”
    add :: (Int) -> (Int -> Int)
    add x = (+) x
    
    -- “To add, call (+).”
    add :: (Int -> Int -> Int)
    add = (+)
    

    更准确地说,如果你有f x = g x,而x 没有出现在g 中,那么你可以写成f = g

    一个常见的错误是想知道为什么f x = g . h x 不能写成f = g . h。它不符合模式,因为(.) 运算符是f 主体中的顶级表达式:它实际上是f x = (.) g (h x)。您可以将其写为f x = (((.) g) . h) x,然后使用Functor 实例为-> 将其缩减为f = (.) g . hf = fmap g . h,但这不被认为是非常可读的。

    为什么sortInsertion中insert的参数翻转了

    foldrfoldl的函数参数有不同的参数顺序:

    foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
    foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
    

    或者,使用更详细的类型变量名称:

    foldr
      :: (Foldable container)
      => (element -> accumulator -> accumulator)
      -> accumulator -> container element -> accumulator
    
    foldl
      :: (Foldable container)
      => (accumulator -> element -> accumulator)
      -> accumulator -> container element -> accumulator
    

    这只是折叠关联方向的助记符:

    foldr f z [a, b, c, d]
    ==
    f a (f b (f c (f d z)))  -- accumulator on the right (second argument)
    
    foldl f z [a, b, c, d]
    ==
    f (f (f (f z a) b) c) d  -- accumulator on the left (first argument)
    

    【讨论】:

      【解决方案2】:

      那是偏函数应用。

      map' f = foldr (\x acc -> (f x):acc) [] 
      

      一样
      map' f xs = foldr (\x acc -> (f x):acc) [] xs
      

      如果你在两边都省略了xs

      但是,除了这个解释之外,我认为您需要一本 Haskell 初学者书籍。考虑LYAH

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-04
        • 1970-01-01
        • 2015-01-08
        • 1970-01-01
        • 2016-11-05
        • 1970-01-01
        • 2018-08-16
        相关资源
        最近更新 更多