Skip to content

Commit 46cb1af

Browse files
Xingye-Dujingulysses4ever
authored andcommitted
Adjust the details
1 parent 0280f45 commit 46cb1af

1 file changed

Lines changed: 15 additions & 15 deletions

File tree

source_md/higher-order-functions.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -675,56 +675,56 @@ Sometimes you don't even have to do that.
675675
The `sum` function can be implemented pretty much the same with a left and right fold.
676676
*One big difference is that right folds work on infinite lists, whereas left ones don't!*
677677

678-
How `foldr` works with infinite lists
678+
How `foldr` works with infinite lists? Recall the definition of `foldr`:
679679

680-
Recall the definition of `foldr`:
681680
```{.haskell:hs}
682681
foldr f acc [] = acc
683682
foldr f acc (x:xs) = f x (foldr f acc xs)
684683
```
684+
685685
The key insight is that the recursive call `foldr f acc xs` is passed as an argument to the function `f`. Because Haskell is lazy, if `f` never uses its second argument, the recursive call is never evaluated. This allows `foldr` to terminate on infinite lists, provided `f` is lazy in its right argument.
686686

687-
Example: Checking for a Value in an infinite list
687+
Example: Checking for a Value in an infinite list. Suppose we want to check if `3` appears in an infinite list `[1..]`. We can use `foldr` like this:
688688

689-
Suppose we want to check if `3` appears in an infinite list `[1..]`. We can use `foldr` like this:
690689
```{.haskell:hs}
691690
containsThree :: [Int] -> Bool
692691
containsThree = foldr (\x rest -> if x == 3 then True else rest) False
693692
```
693+
694694
Let's unfold this step-by-step on the infinite list `[1,2,3,4,...]`:
695-
1. Start: foldr (...) False [1,2,3,4,...]
695+
696+
1. Start: `foldr (...) False [1,2,3,4,...]`
696697
2. For `x=1`: `if 1 == 3 then True else (foldr (...) False [2,3,4,...])` -> `1 /= 3`, so this becomes `foldr (...) False [2,3,4,...]` (we recurse).
697698
3. For `x=2`: `if 2 == 3 then True else (foldr (...) False [3,4,5,...])` -> `2 /= 3`, so this becomes `foldr (...) False [3,4,5,...]` (we recurse again).
698699
4. For `x=3`: `if 3 == 3 then True else (foldr (...) False [4,5,6,...])` -> `3 == 3` is `True`! *Here, `f` ignores the recursive call (the [4,5,6,...] part) and returns True immediately*.
699700

700-
Why `foldl` Fails with Infinite Lists
701+
Why `foldl` Fails with Infinite Lists? Now, contrast this with `foldl`'s definition:
701702

702-
Now, contrast this with foldl's definition:
703703
```{.haskell:hs}
704704
foldl f acc [] = acc
705705
foldl f acc (x:xs) = foldl f (f acc x) xs
706706
```
707+
707708
Notice that `foldl` always makes a recursive call first, passing `f acc x` as the new accumulator. This means:
708709
Even if the accumulator becomes True at some point, foldl will still continue recursing down the list.
709-
For an infinite list, this leads to infinite recursion (it never stops).
710+
For an infinite list, this leads to infinite recursion (it never stops). If we try to implement containsThree with `foldl`:
710711

711-
Example: `foldl` on the Same Problem
712-
713-
If we try to implement containsThree with `foldl`:
714712
```{.haskell:hs}
715713
containsThreeFoldl :: [Int] -> Bool
716714
containsThreeFoldl = foldl (\acc x -> if x == 3 then True else acc) False
717715
```
718-
1. Unfolding on `[1,2,3,4,...]`:
719-
2. Start: `acc = False`, list [1,2,3,4,...].
716+
717+
Unfolding on `[1,2,3,4,...]`:
718+
719+
1. Start: `acc = False`, list [1,2,3,4,...].
720720
3. Compute `f False 1` -> `if 1==3 then True else False` -> `False`. Recurse: `foldl (...) False [2,3,4,...]`.
721721
4. Compute `f False 2` -> `False`. Recurse: `foldl (...) False [3,4,5,...]`.
722722
5. Compute `f False 3` -> `True`. But now we must recurse: `foldl (...) True [4,5,6,...]`.
723723
6. Compute `f True 4` -> `True` (since 4 /= 3, it returns the accumulator True). But we recurse again: `foldl (...) True [5,6,7,...]`.
724724
7. This continues forever. Even though we found 3, we never stop.
725725

726-
`foldr` can terminate on infinite lists if the function `f` is lazy in its right argument (i.e., `f` can short-circuit by ignoring the recursive result).
727-
`foldl` always processes the list from left to right and cannot short-circuit in the same way, so it fails on infinite lists.
726+
The `foldr` function can terminate on infinite lists if the function `f` is lazy in its right argument (i.e., `f` can short-circuit by ignoring the recursive result).
727+
The `foldl` function always processes the list from left to right and cannot short-circuit in the same way, so it fails on infinite lists.
728728
This is why `foldr` is often more suitable for working with infinite lists. Just remember: *the function `f` must be lazy in its right argument for `foldr` to terminate early*.
729729

730730
**Folds can be used to implement any function where you traverse a list once, element by element, and then return something based on that.

0 commit comments

Comments
 (0)