【问题标题】:How does scanr work? Haskell扫描仪如何工作?哈斯克尔
【发布时间】:2013-07-30 17:25:14
【问题描述】:

我一直在搞乱一些 Haskell 函数,有些我明白,有些不明白。

例如,如果我们这样做:scanl (+) 0 [1..3] 我的理解如下:

1. the accumulator is 0                  acc         = 0    |
2. (+) applied to acc and first el       acc = 0 + 1 = 1    |
3. (+) applied to latest acc and snd el  acc = 1 + 2 = 3    |
4. (+) applied to latest acc and third   acc = 3 + 3 = 6    V

现在,当我们列出列表时,我们会得到[0, 1, 3, 6]

但我似乎无法理解scanr (+) 0 [1..3] 是如何给我的:[6,5,3,0] 也许scanr 的工作方式如下?

1. the first element in the list is the sum of all other + acc
2. the second element is the sum from right to left (<-) of the last 2 elements
3. the third element is the sum of first 2...

我不知道这是否是模式。

【问题讨论】:

    标签: list function haskell higher-order-functions fold


    【解决方案1】:

    scanr 对应于foldrscanl 对应于foldlfoldr 从右边工作:

    foldr (+) 0 [1,2,3] =
      (1 + (2 + (3 +   0))) =
      (1 + (2 +    3)) =
      (1 +    5) =
         6
    -- [ 6,   5,   3,   0 ]
    

    scanr 只是按顺序显示中间结果:[6,5,3,0]。可以定义为

    scanr (+) z xs = foldr g [z] xs
      where
      g x ys@(y:_) = x+y : ys
    

    scanl 虽然应该像这样工作

    scanl (+) 0 [1,2,3] =
      0 : scanl (+) (0+1) [2,3] =
      0 : 1 : scanl (+) (1+2) [3] =
      0 : 1 : 3 : scanl (+) (3+3) [] =
      0 : 1 : 3 : [6]
    

    应该是这样的

    scanl (+) z xs = foldr f h xs z
       where h      z = [z]
             f x ys z = z : ys (z + x)
    

    【讨论】:

      【解决方案2】:

      scanlscanr 用于显示每次迭代时累加器的值。 scanl 从左到右迭代,scanr 从右到左迭代。

      考虑以下示例:

      scanl (+) 0 [1, 2, 3]
      
      -- 0. `scanl` stores 0 as the accumulator and in the output list [0]
      -- 1. `scanl` adds 0 and 1 and stores 1 as the accumulator and in the output list [0, 1]
      -- 2. `scanl` adds 1 and 2 and stores 3 as the accumulator and in the output list [0, 1, 3]
      -- 3. `scanl` adds 3 and 3 and stores 6 as the accumulator and in the output list [0, 1, 3, 6]
      -- 4. `scanl` returns the output list [0, 1, 3, 6]
      

      如您所见,scanl 在迭代列表时存储累加器的结果。 scanr 也是如此,但列表是反向迭代的。

      这是另一个例子:

      scanl (flip (:)) [] [1, 2, 3]
      
      -- [[], [1], [2,1], [3,2,1]]
      
      scanr       (:)  [] [1, 2, 3]
      
      -- [[1,2,3], [2,3], [3], []]
      

      【讨论】:

        猜你喜欢
        • 2021-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多