You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: source_md/higher-order-functions.md
+15-15Lines changed: 15 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -675,56 +675,56 @@ Sometimes you don't even have to do that.
675
675
The `sum` function can be implemented pretty much the same with a left and right fold.
676
676
*One big difference is that right folds work on infinite lists, whereas left ones don't!*
677
677
678
-
How `foldr` works with infinite lists
678
+
How `foldr` works with infinite lists? Recall the definition of `foldr`:
679
679
680
-
Recall the definition of `foldr`:
681
680
```{.haskell:hs}
682
681
foldr f acc [] = acc
683
682
foldr f acc (x:xs) = f x (foldr f acc xs)
684
683
```
684
+
685
685
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.
686
686
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:
688
688
689
-
Suppose we want to check if `3` appears in an infinite list `[1..]`. We can use `foldr` like this:
690
689
```{.haskell:hs}
691
690
containsThree :: [Int] -> Bool
692
691
containsThree = foldr (\x rest -> if x == 3 then True else rest) False
693
692
```
693
+
694
694
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,...]`
696
697
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).
697
698
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).
698
699
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*.
699
700
700
-
Why `foldl` Fails with Infinite Lists
701
+
Why `foldl` Fails with Infinite Lists? Now, contrast this with `foldl`'s definition:
701
702
702
-
Now, contrast this with foldl's definition:
703
703
```{.haskell:hs}
704
704
foldl f acc [] = acc
705
705
foldl f acc (x:xs) = foldl f (f acc x) xs
706
706
```
707
+
707
708
Notice that `foldl` always makes a recursive call first, passing `f acc x` as the new accumulator. This means:
708
709
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`:
710
711
711
-
Example: `foldl` on the Same Problem
712
-
713
-
If we try to implement containsThree with `foldl`:
714
712
```{.haskell:hs}
715
713
containsThreeFoldl :: [Int] -> Bool
716
714
containsThreeFoldl = foldl (\acc x -> if x == 3 then True else acc) False
5. Compute `f False 3` -> `True`. But now we must recurse: `foldl (...) True [4,5,6,...]`.
723
723
6. Compute `f True 4` -> `True` (since 4 /= 3, it returns the accumulator True). But we recurse again: `foldl (...) True [5,6,7,...]`.
724
724
7. This continues forever. Even though we found 3, we never stop.
725
725
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.
728
728
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*.
729
729
730
730
**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