【问题标题】:How does fold works for empty list?fold 如何处理空列表?
【发布时间】:2017-06-21 19:57:36
【问题描述】:

当我们折叠一个包含一个或多个元素的列表时,如下所示:

foldr (+) 0 [1,2,3]

我们得到:

foldr (+) 0 (1 : 2 : 3 : [])

foldr (+) 1 + (2 +(3 + 0)) // 6

现在当列表为空时:

 foldr (+) 0 []

结果:foldr (+) 0 ([])

由于 (+) 是二元运算符,它需要两个参数来完成,但这里我们最终得到 (+) 0。如何导致部分应用函数为0而不抛出错误。

【问题讨论】:

  • (+0)foldr (+) 0 [] 不同
  • 您可以将foldr f z xs 视为将xs 中的所有: 替换为f 并将[](如果存在)替换为z。所以foldr (+) 0 []0替换了[],并且没有:可以替换,所以+永远不会被使用。

标签: haskell fold


【解决方案1】:

简答:你得到初始值z

如果您给foldlfoldr 一个空列表,那么它会返回initial 值。 foldr :: (a -> b -> b) -> b -> t a -> b 的作用类似于:

foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)

因此,由于没有 x1, ..., xn,因此永远不会应用该函数,并返回 z

我们也可以查看source code:

foldr            :: (a -> b -> b) -> b -> [a] -> b
-- foldr _ z []     =  z
-- foldr f z (x:xs) =  f x (foldr f z xs)
{-# INLINE [0] foldr #-}
-- Inline only in the final stage, after the foldr/cons rule has had a chance
-- Also note that we inline it when it has *two* parameters, which are the
-- ones we are keen about specialising!
foldr k z = go
          where
            go []     = z
            go (y:ys) = y `k` go ys

因此,如果我们给foldr 一个空列表,那么go 将立即处理该空列表,并返回初始值z

因此,更简洁的语法(并且效率稍低,如函数注释中所述)将是:

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)

注意 - 根据f 的实现 - 可以在无限列表上使用foldr:如果在某些时候f 只查看初始值,然后返回一个值,那么递归部分可以丢弃。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 2016-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多