文件夹如何工作?

发布于 2024-08-12 05:36:51 字数 332 浏览 3 评论 0原文

谁能解释一下 foldr工作吗?

举这些例子:

Prelude> foldr (-) 54 [10, 11]
53
Prelude> foldr (\x y -> (x+y)/2) 54 [12, 4, 10, 6]
12.0

我对这些处决感到困惑。有什么建议吗?

Can anybody explain how does foldr work?

Take these examples:

Prelude> foldr (-) 54 [10, 11]
53
Prelude> foldr (\x y -> (x+y)/2) 54 [12, 4, 10, 6]
12.0

I am confused about these executions. Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

無處可尋 2024-08-19 05:36:51

理解foldr的最简单方法是重写您要折叠的列表,而不加任何糖分。

[1,2,3,4,5] => 1:(2:(3:(4:(5:[]))))

现在 foldr f x 所做的是,它将每个 : 替换为中缀形式的 f,并将 [] 替换为 x 并评估结果。

例如:

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

[1,2,3] === 1:(2:(3:[]))

所以

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

The easiest way to understand foldr is to rewrite the list you're folding over without the sugar.

[1,2,3,4,5] => 1:(2:(3:(4:(5:[]))))

now what foldr f x does is that it replaces each : with f in infix form and [] with x and evaluates the result.

For example:

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

[1,2,3] === 1:(2:(3:[]))

so

sum [1,2,3] === 1+(2+(3+0)) = 6
一片旧的回忆 2024-08-19 05:36:51

foldr 从列表的右端开始,并使用您提供的函数将每个列表条目与累加器值组合起来。结果是所有列表元素“折叠”后累加器的最终值。它的类型是:

foldr :: (a -> b -> b) -> b -> [a] -> b

从这里你可以看到列表元素(a类型)是给定函数的第一个参数,累加器(b类型)是第二个。

对于第一个例子:

Starting accumulator = 54
11 -   54  = -43
10 - (-43) =  53

        ^  Result from the previous line

 ^ Next list item

所以你得到的答案是 53。

第二个例子:

Starting accumulator = 54
(6  + 54) / 2 = 30
(10 + 30) / 2 = 20
(4  + 20) / 2 = 12
(12 + 12) / 2 = 12

所以结果是 12。

编辑:我的意思是添加,这是针对有限列表的。 foldr 也可以处理无限列表,但我认为最好先了解有限情况。

foldr begins at the right-hand end of the list and combines each list entry with the accumulator value using the function you give it. The result is the final value of the accumulator after "folding" in all the list elements. Its type is:

foldr :: (a -> b -> b) -> b -> [a] -> b

and from this you can see that the list element (of type a) is the first argument to the given function, and the accumulator (of type b) is the second.

For your first example:

Starting accumulator = 54
11 -   54  = -43
10 - (-43) =  53

        ^  Result from the previous line

 ^ Next list item

So the answer you got was 53.

The second example:

Starting accumulator = 54
(6  + 54) / 2 = 30
(10 + 30) / 2 = 20
(4  + 20) / 2 = 12
(12 + 12) / 2 = 12

So the result is 12.

Edit: I meant to add, that's for finite lists. foldr can also work on infinite lists but it's best to get your head around the finite case first, I think.

不再见 2024-08-19 05:36:51

它有助于理解 foldrfoldl 之间的区别。为什么 foldr 称为“右折叠”?

最初我认为这是因为它从右到左消耗元素。然而,foldrfoldl 都从左到右使用列表。

  • foldl 从左到右评估(左关联)
  • foldr 从右到左评估(右关联)

我们可以通过一个使用关联性很重要的运算符的示例来清楚地阐明这种区别。我们可以使用人类的例子,例如运算符“eats”:

foodChain = (human : (shark : (fish : (algae : []))))

foldl step [] foodChain
  where step eater food = eater `eats` food  -- note that "eater" is the accumulator and "food" is the element

foldl `eats` [] (human : (shark : (fish : (algae : []))))
  == foldl eats (human `eats` shark)                              (fish : (algae : []))
  == foldl eats ((human `eats` shark) `eats` fish)                (algae : [])
  == foldl eats (((human `eats` shark) `eats` fish) `eats` algae) []
  ==            (((human `eats` shark) `eats` fish) `eats` algae)

这个foldl的语义是:一个人吃了一些鲨鱼,然后吃掉鲨鱼的同一个人又吃了一些鱼,等等。吃者是累加者。

对比一下:

foldr step [] foodChain
    where step food eater = eater `eats` food.   -- note that "eater" is the element and "food" is the accumulator

foldr `eats` [] (human : (shark : (fish : (algae : []))))
  == foldr eats (human `eats` shark)                              (fish : (algae : []))))
  == foldr eats (human `eats` (shark `eats` (fish))               (algae : [])
  == foldr eats (human `eats` (shark `eats` (fish `eats` algae))) []
  ==            (human `eats` (shark `eats` (fish `eats` algae) 

这个foldr的语义是:一个人吃掉了一条已经吃掉了一条鱼的鲨鱼,而这条鱼已经吃掉了一些藻类。食物是蓄能器。

foldlfoldr 都是从左到右“剥离”吃者,所以这不是我们将foldl称为“左折叠”的原因。相反,评估的顺序很重要。

It helps to understand the distinction between foldr and foldl. Why is foldr called "fold right"?

Initially I thought it was because it consumed elements from right to left. Yet both foldr and foldl consume the list from left to right.

  • foldl evaluates from left to right (left-associative)
  • foldr evaluates from right to left (right-associative)

We can make this distinction clear with an example that uses an operator for which associativity matters. We could use a human example, such as the operator, "eats":

foodChain = (human : (shark : (fish : (algae : []))))

foldl step [] foodChain
  where step eater food = eater `eats` food  -- note that "eater" is the accumulator and "food" is the element

foldl `eats` [] (human : (shark : (fish : (algae : []))))
  == foldl eats (human `eats` shark)                              (fish : (algae : []))
  == foldl eats ((human `eats` shark) `eats` fish)                (algae : [])
  == foldl eats (((human `eats` shark) `eats` fish) `eats` algae) []
  ==            (((human `eats` shark) `eats` fish) `eats` algae)

The semantics of this foldl is: A human eats some shark, and then the same human who has eaten shark then eats some fish, etc. The eater is the accumulator.

Contrast this with:

foldr step [] foodChain
    where step food eater = eater `eats` food.   -- note that "eater" is the element and "food" is the accumulator

foldr `eats` [] (human : (shark : (fish : (algae : []))))
  == foldr eats (human `eats` shark)                              (fish : (algae : []))))
  == foldr eats (human `eats` (shark `eats` (fish))               (algae : [])
  == foldr eats (human `eats` (shark `eats` (fish `eats` algae))) []
  ==            (human `eats` (shark `eats` (fish `eats` algae) 

The semantics of this foldr is: A human eats a shark which has already eaten a fish, which has already eaten some algae. The food is the accumulator.

Both foldl and foldr "peel off" eaters from left to right, so that's not the reason we refer to foldl as "left fold". Instead, the order of evaluation matters.

妞丶爷亲个 2024-08-19 05:36:51

想想 foldr定义

 -- if the list is empty, the result is the initial value z
 foldr f z []     = z                  
 -- if not, apply f to the first element and the result of folding the rest 
 foldr f z (x:xs) = f x (foldr f z xs)

例如 foldr (-) 54 [10,11] 必须等于 (-) 10 (foldr (-) 54 [11]),即再次展开,等于 (-) 10 ((-)11 54)。所以内部运算为11 - 54,即-43;外部操作是 10 - (-43),即 10 + 43,因此正如您所观察到的 53 。对第二种情况执行类似的步骤,您将再次看到结果如何形成!

Think about foldr's very definition:

 -- if the list is empty, the result is the initial value z
 foldr f z []     = z                  
 -- if not, apply f to the first element and the result of folding the rest 
 foldr f z (x:xs) = f x (foldr f z xs)

So for example foldr (-) 54 [10,11] must equal (-) 10 (foldr (-) 54 [11]), i.e. expanding again, equal (-) 10 ((-) 11 54). So the inner operation is 11 - 54, that is, -43; and the outer operation is 10 - (-43), that is, 10 + 43, therefore 53 as you observe. Go through similar steps for your second case, and again you'll see how the result forms!

jJeQQOZ5 2024-08-19 05:36:51

foldr 表示从右侧折叠,因此 foldr (-) 0 [1, 2, 3] 生成 (1 - (2 - (3 - 0)) )。相比之下,foldl 生成(((0 - 1) - 2) - 3)

当运算符不可交换 foldlfoldr 会得到不同的结果。

在您的例子中,第一个示例扩展为 (10 - (11 - 54)) ,给出 53。

foldr means fold from the right, so foldr (-) 0 [1, 2, 3] produces (1 - (2 - (3 - 0))). In comparison foldl produces (((0 - 1) - 2) - 3).

When the operators are not commutative foldl and foldr will get different results.

In your case, the first example expands to (10 - (11 - 54)) which gives 53.

红衣飘飘貌似仙 2024-08-19 05:36:51

理解foldr的一个简单方法是:它将每个列表构造函数替换为所提供函数的应用程序。你的第一个例子将转换为:

10 - (11 - 54)

from:

10 : (11 : [])

我从 Haskell Wikibook 得到的一个很好的建议在这里可能有一些用处:

作为一项规则,您应该在可能无限或折叠正在构建数据结构的列表上使用 foldr ,如果列表已知,则应使用 foldl'是有限的并且归结为单个值。 foldl(不带勾)应该很少使用。

An easy way to understand foldr is this: It replaces every list constructor with an application of the function provided. Your first example would translate to:

10 - (11 - 54)

from:

10 : (11 : [])

A good piece of advice that I got from the Haskell Wikibook might be of some use here:

As a rule you should use foldr on lists that might be infinite or where the fold is building up a data structure, and foldl' if the list is known to be finite and comes down to a single value. foldl (without the tick) should rarely be used at all.

葬シ愛 2024-08-19 05:36:51

我一直认为 http://foldr.com 是一个有趣的插图。请参阅 Lambda Ultimate 帖子。

I've always thought http://foldr.com to be a fun illustration. See the Lambda the Ultimate post.

灯下孤影 2024-08-19 05:36:51

仔细阅读此处提供的其他答案并对其进行比较应该已经清楚了这一点,但值得注意的是,所接受的答案可能会对初学者有点误导。正如其他评论者所指出的,Haskell 中执行的计算foldr 并不是“从列表的右手端开始”;而是“从列表的右端开始”。否则,foldr 永远无法在无限列表上工作(在正确的条件下,它在 Haskell 中是这样做的)。

Haskell 的源代码 foldr 函数应该明确这一点:

foldr k z = go
          where
            go []     = z
            go (y:ys) = y `k` go ys

每个递归计算将最左边的原子列表项与列表尾部的递归计算结合起来,即:

a\[1\] `f` (a[2] `f` (a[3] `f` ... (a[n-1] `f` a[n])  ...))

其中 a[n]是初始累加器。

因为归约是“在 Haskell 中延迟完成的”,所以它实际上是从左侧开始。这就是我们所说的“惰性求值”,也是 Haskell 的一个著名的显着特征。这对于理解 Haskell 的 foldr 的操作很重要;因为,事实上,foldr 构建并减少计算从左侧递归,二元运算符可以电路有机会在适当的情况下允许无限列表减少foldr。

对于初学者来说,说 foldr 中的 r(“右”)和 l(“左”)会减少很多混乱。和 foldl 指的是右关联性左关联性,要么就这样,要么尝试解释 Haskell 惰性求值机制的含义。

为了完成您的示例,按照 foldr 源代码,我们构建了以下表达式:

Prelude> foldr (-) 54 [10, 11]

->

10 - [11 - 54] = 53

再次:

foldr (\x y -> (x + y) / 2) 54 [12, 4, 10, 6]

->

(12 + (4 + (10 + (6 + 54) / 2) / 2) / 2) / 2 = 12

Careful readings of -- and comparisons between -- the other answers provided here should already make this clear, but it's worth noting that the accepted answer might be a bit misleading to beginners. As other commenters have noted, the computation foldr performs in Haskell does not "begin at the right hand end of the list"; otherwise, foldr could never work on infinite lists (which it does in Haskell, under the right conditions).

The source code for Haskell's foldr function should make this clear:

foldr k z = go
          where
            go []     = z
            go (y:ys) = y `k` go ys

Each recursive computation combines the left-most atomic list item with a recursive computation over the tail of the list, viz:

a\[1\] `f` (a[2] `f` (a[3] `f` ... (a[n-1] `f` a[n])  ...))

where a[n] is the initial accumulator.

Because reduction is done "lazily in Haskell," it actually begins at the left. This is what we mean by "lazy evaluation," and it's famously a distinguishing feature of Haskell. And it's important in understanding the operation of Haskell's foldr; because, in fact, foldr builds up and reduces computations recursively from the left, binary operators that can short-circuit have an opportunity to, allowing infinite lists to be reduced by foldr under appropriate circumstances.

It will lead to far less confusion to beginners to say rather that the r ("right") and l ("left") in foldr and foldl refer to right associativity and left associativity and either leave it at that, or try and explain the implications of Haskell's lazy evaluation mechanism.

To work through your examples, following the foldr source code, we build up the following expression:

Prelude> foldr (-) 54 [10, 11]

->

10 - [11 - 54] = 53

And again:

foldr (\x y -> (x + y) / 2) 54 [12, 4, 10, 6]

->

(12 + (4 + (10 + (6 + 54) / 2) / 2) / 2) / 2 = 12
想念有你 2024-08-19 05:36:51

我认为以简单的方式实现map、foldl 和foldr 有助于解释它们的工作原理。工作示例也有助于我们的理解。

  myMap f [] = []
  myMap f (x:xs) = f x : myMap f xs

  myFoldL f i [] = i
  myFoldL f i (x:xs) = myFoldL f (f i x) xs

  > tail [1,2,3,4] ==> [2,3,4]
  > last [1,2,3,4] ==> 4
  > head [1,2,3,4] ==> 1
  > init [1,2,3,4] ==> [1,2,3]

  -- where f is a function,
  --  acc is an accumulator which is given initially
  --  l is a list.
  --
  myFoldR' f acc [] = acc
  myFoldR' f acc l = myFoldR' f (f acc (last l)) (init l)

  myFoldR f z []     = z
  myFoldR f z (x:xs) = f x (myFoldR f z xs)

  > map (\x -> x/2) [12,4,10,6] ==> [6.0,2.0,5.0,3.0]
  > myMap (\x -> x/2) [12,4,10,6] ==> [6.0,2.0,5.0,3.0]

  > foldl (\x y -> (x+y)/2) 54 [12, 4, 10, 6] ==> 10.125
  > myFoldL (\x y -> (x+y)/2) 54 [12, 4, 10, 6] ==> 10.125

    foldl from above: Starting accumulator = 54
      (12  + 54) / 2 = 33
      (4 + 33) / 2 = 18.5
      (10  + 18.5) / 2 = 14.25
      (6 + 14.25) / 2 = 10.125`

 > foldr (++) "5" ["1", "2", "3", "4"] ==> "12345"

 > foldl (++) "5" ["1", "2", "3", "4"] ==> “51234"

 > foldr (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
 > myFoldR' (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
 > myFoldR (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12

    foldr from above: Starting accumulator = 54
        (6  + 54) / 2 = 30
        (10 + 30) / 2 = 20
        (4  + 20) / 2 = 12
        (12 + 12) / 2 = 12

I think that implementing map, foldl and foldr in a simple fashion helps explain how they work. Worked examples also aid in our understanding.

  myMap f [] = []
  myMap f (x:xs) = f x : myMap f xs

  myFoldL f i [] = i
  myFoldL f i (x:xs) = myFoldL f (f i x) xs

  > tail [1,2,3,4] ==> [2,3,4]
  > last [1,2,3,4] ==> 4
  > head [1,2,3,4] ==> 1
  > init [1,2,3,4] ==> [1,2,3]

  -- where f is a function,
  --  acc is an accumulator which is given initially
  --  l is a list.
  --
  myFoldR' f acc [] = acc
  myFoldR' f acc l = myFoldR' f (f acc (last l)) (init l)

  myFoldR f z []     = z
  myFoldR f z (x:xs) = f x (myFoldR f z xs)

  > map (\x -> x/2) [12,4,10,6] ==> [6.0,2.0,5.0,3.0]
  > myMap (\x -> x/2) [12,4,10,6] ==> [6.0,2.0,5.0,3.0]

  > foldl (\x y -> (x+y)/2) 54 [12, 4, 10, 6] ==> 10.125
  > myFoldL (\x y -> (x+y)/2) 54 [12, 4, 10, 6] ==> 10.125

    foldl from above: Starting accumulator = 54
      (12  + 54) / 2 = 33
      (4 + 33) / 2 = 18.5
      (10  + 18.5) / 2 = 14.25
      (6 + 14.25) / 2 = 10.125`

 > foldr (++) "5" ["1", "2", "3", "4"] ==> "12345"

 > foldl (++) "5" ["1", "2", "3", "4"] ==> “51234"

 > foldr (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
 > myFoldR' (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
 > myFoldR (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12

    foldr from above: Starting accumulator = 54
        (6  + 54) / 2 = 30
        (10 + 30) / 2 = 20
        (4  + 20) / 2 = 12
        (12 + 12) / 2 = 12
拧巴小姐 2024-08-19 05:36:51

好的,让我们看看参数:

  • 一个函数(它接受一个列表元素和一个与它返回的值相同类型的值(可能的部分结果));
  • 的初始结果的规范
  • 空列表特殊情况列表

;返回值:

  • 一些最终结果

它首先将函数应用于列表中的最后一个元素和空列表结果。然后,它使用此结果和前一个元素重新应用该函数,依此类推,直到它使用某个当前结果和列表的第一个元素来返回最终结果。

Fold 使用接受元素和一些先前折叠结果的函数围绕初始结果“折叠”列表。它对每个元素重复此操作。因此,foldr 从列表的末尾或列表的右侧开始执行此操作。

folr femptyresult [1,2,3,4] 变成
f(1, f(2, f(3, f(4, 空结果) ) ) )。现在只需在评估中遵循括号即可。

需要注意的一件重要事情是,提供的函数 f 必须将其自己的返回值作为第二个参数处理,这意味着两者必须具有相同的类型。

资料来源:我的帖子,我从如果您认为它可能有帮助,请使用命令式非柯里化 javascript 观点。

Ok, lets look at the arguments:

  • a function (that takes a list element and a value (a possible partial result) of the same kind of the value it returns);
  • a specification of the initial result for the empty list special case
  • a list;

return value:

  • some final result

It first applies the function to the last element in the list and the empty list result. It then reapplies the function with this result and the previous element, and so forth until it takes some current result and the first element of the list to return the final result.

Fold "folds" a list around an initial result using a function that takes an element and some previous folding result. It repeats this for each element. So, foldr does this starting at the end off the list, or the right side of it.

folr f emptyresult [1,2,3,4] turns into
f(1, f(2, f(3, f(4, emptyresult) ) ) ). Now just follow parenthesis in evaluation and that's it.

One important thing to notice is that the supplied function f must handle its own return value as its second argument which implies both must have the same type.

Source: my post where I look at it from an imperative uncurried javascript perspective if you think it might help.

誰認得朕 2024-08-19 05:36:51

此 wiki 页面中的图像可视化了 foldr(以及 foldl)的概念:

例如,foldr (-) 0 的结果[1,2,3] 是 2,可以形象化为:

  -
 / \
1   -
   / \
  2   -
     / \
    3   0

即(从下到上):

1 - ( -1 )      = 2
    2 - ( 3 )
        3 - 0

所以 foldr (\xy -> (x+y)/2) 54 [12, 4, 10, 6] 通过以下方式计算:

12 `f` (12.0)          = 12.0
     4 `f` (20.0)
        10 `f` (30.0)
             6 `f` 54

The images in this wiki page visualize the idea of foldr (and foldl also):

For example, the result of foldr (-) 0 [1,2,3] is 2. It can be visualized as:

  -
 / \
1   -
   / \
  2   -
     / \
    3   0

That is (from bottom to the top):

1 - ( -1 )      = 2
    2 - ( 3 )
        3 - 0

So foldr (\x y -> (x+y)/2) 54 [12, 4, 10, 6] is being computed through:

12 `f` (12.0)          = 12.0
     4 `f` (20.0)
        10 `f` (30.0)
             6 `f` 54
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文