#foldL
Just published on the #Haskell blog: A deep dive into "Differences between `foldl` and `foldr`"
blog.haskell.org/foldl-and-fo... originally by Alexis King
Differences between `foldl` and `foldr` | The Haskell Programming Language's blog
`foldl` and `foldr` can be confusing, so let's work out what's up
blog.haskell.org
September 26, 2026 at 10:33 AM
FOLDL? C O M M U N I S M
November 28, 2024 at 4:00 PM
he's a 10 but he calls foldl "reduce"
February 27, 2024 at 7:15 PM
i love programming, it’s one of my favorite poetrys 🫀,
December 31, 2024 at 1:18 AM
for the most part you can ignore this stuff in application code and fix it when it shows up in a profiler :) also when in doubt foldl'

source: production Haskell experience
September 27, 2026 at 8:13 PM
Just uploaded a new release of the `foldl` package. This release has a bunch of new instance and utilities added by one very helpful outside contributor (Topsii):

hackage.haskell.org/package/fold...
Changelog for foldl-1.4.18 | Hackage
hackage.haskell.org
December 20, 2024 at 5:16 AM
the foldl function, or as I like to call it: "the function whose only purpose is to reverse a list"
August 13, 2025 at 4:29 AM
i had to look up the order of arguments for the foldl implementation of my own programming language, whose stdlib i fully designed and implemented myself

its so over for me
the year is 2030.

humanity has finally embraced functional programming, and there are now more functional languages than any other paradigm. you might even use 3 or 4 of them daily.

each language has a unique, incompatible signature for the function argument provided in foldl.
June 22, 2025 at 9:23 AM
these large scary math symbols are just foldls on lists btw
January 23, 2025 at 3:27 AM
the year is 2030.

humanity has finally embraced functional programming, and there are now more functional languages than any other paradigm. you might even use 3 or 4 of them daily.

each language has a unique, incompatible signature for the function argument provided in foldl.
April 10, 2025 at 2:41 PM
isn’t folds being monoids kinda the basis for the foldl package?
September 4, 2026 at 6:48 AM
Day 8 done. Yippee.

I still hate grids, but this one was bare able I guess.

I am so glad that `any` and `all` exist, so much nicer than writing my 100th foldl' of the day.
Got my day 7 done >.<

Probably the best one yet for functional languages.

I think this meme suits this well though
December 8, 2024 at 10:06 PM
summation symbol is just a foldl (+) 0
February 26, 2026 at 11:36 PM
Differences between `foldl` and `foldr`
_Editor's note: This article is a reproduction of a seminal explanation of the differences between foldr and foldl, both strict and lazy versions. As it has been used consistently to teach newcomers since its first appearance on hasura/graphql-engine!2933 on the 26th September 2019, we believe that it ought to be preserved in the blog. Our many thanks to Alexis King for giving her permission to do so._ * * * To start, you have to understand that `foldl` and `foldr` are _not_ folds “from the left” and “from the right.” Both `foldl` and `foldr` traverse the structure in the same order, which in the case of lists means left to right. The difference is the fold’s _associativity_. ### `foldl` vs `foldr` illustrated The best way to think about this is with an illustration. When you write foldl (⨂) _v_ [_e_ 0, _e_ 1, _e_ 2, ..., _e_ _n_ −1, _e_ _n_] you’re performing the following computation: ( ... (((_v_ ⨂ _e_ 0) ⨂ _e_ 1) ⨂ _e_ 2) ⨂ ... ⨂ _e_ _n_ −1) ⨂ _e_ _n_ In contrast, when you write foldr (⨂) _v_ [_e_ 0, _e_ 1, _e_ 2, ..., _e_ _n_ −1, _e_ _n_] you’re performing this computation: _e_ 0 ⨂ (_e_ 1 ⨂ (_e_ 2 ⨂ ... ⨂ (_e_ _n_ −1 ⨂ (_e_ _n_ ⨂ _v_)) ... )) See the difference? In both expressions, the elements of the list appear in the expression in the same order—from left to right—but the _grouping_ changes. With `foldl`, the applications of `(⨂)` are left-associated, while with `foldr`, they’re right-associated. ### `foldl` vs. `foldr`, strictly The question is: how does this difference actually impact the behavior of a program? Well, let’s start by first thinking about what the difference would be in a strict language. In a strict language, evaluation order always proceeds from the “inside out,” starting with the most deeply nested expression. Let’s think about that in the context of `foldl` first. Let’s say we wrote this expression: foldl (+) 0 [1, 2, 3, 4] By the above illustration, we know that expression is equivalent to this one: (((0 + 1) + 2) + 3) + 4 Reducing from the inside out, we get the following reduction sequence: foldl (+) 0 [1, 2, 3, 4] = (((0 + 1) + 2) + 3) + 4 = (( 1 + 2) + 3) + 4 = ( 3 + 3) + 4 = 6 + 4 = 10 In contrast, if we had used `foldr`, we’d get the same result (since `(+)` is an associative, commutative operation), but with a slightly different reduction sequence: foldr (+) 0 [1, 2, 3, 4] = 1 + (2 + (3 + (4 + 0))) = 1 + (2 + (3 + 4 )) = 1 + (2 + 7 ) = 1 + 9 = 10 What’s the practical difference between these two things? Well, note the following detail: with `foldl`, to start reducing, we only need the _first_ element of the list, but with `foldr`, we have to start from the _end_ of the list and reduce “backwards.”1 Practically, this means `foldl` can be tail-recursive, reducing as it traverses the list in constant space, while `foldr` cannot be: to reduce a list of length _`n`_ with `foldr`, you need to create _`n`_ stack frames before any reduction can start. 1 This is why `foldr` is sometimes described as “folding from the right”, even though it traverses the list from left to right. As we’ll see, however, this doesn’t actually hold in lazy languages! ### `foldl`, lazily But what about in _lazy_ languages, like Haskell? In a lazy language, evaluation order doesn’t proceed from the “inside out” like it does in strict languages, but rather from the “outside in,” evaluating expressions only as their results are _demanded_. In a strict language, `foldl (+) 0 [1, 2, 3, 4]` doesn’t _actually_ get turned into the expression `(((0 + 1) + 2) + 3) + 4`; as I mentioned earlier, it’s implemented as a tail-recursive loop. But in Haskell, it basically _does_ get expanded into that expression before any reduction starts—each application of `(+)` is lazily suspended in a thunk. If we explicitly denote thunks with ⟨⟩ brackets, the thunk we’ll end up with looks like this: ⟨⟨⟨⟨0 + 1⟩ + 2⟩ + 3⟩ + 4⟩ These thunks will only get forced when the outermost thunk is evaluated, which will cause `(+)` to be applied to the arguments `⟨⟨⟨0 + 1⟩ + 2⟩ + 3⟩` and `4`. Since `(+)` is strict in both its arguments, it will force the next thunk, which will in turn apply `(+)` to `⟨⟨0 + 1⟩ + 2⟩` and `3`, and so on until the whole thunk tree is reduced. The result ends up being the same, but from a practical point of view, this is really bad, because instead of reducing the list in constant space, like we did in the strict language, we’re now creating a thunk linear in the size of the input list! It’s even worse that that, though, because in a strict language, the input list takes up space linear to its own size, so our overall space consumption for producing/consuming the list would simply be a constant factor increase, but in a lazy language, the list itself is more like a _stream_ , which may actually use constant space if the whole stream is not fully realized in memory. By using the lazy `foldl`, we’ve possibly gone from a constant-space algorithm to a linear-space algorithm, which is bad! What we want is to recover the behavior of the strict language’s `foldl`, efficiently updating an accumulator as we traverse the list, not building thunks. Therefore, we need a stricter version of `foldl`, which is exactly what `foldl'` is. `foldl'` places a demand on the `⟨0 + 1⟩` thunk _before_ moving onto the next element of the list, so instead of building a larger `⟨⟨0 + 1⟩ + 2⟩` thunk, it simply builds a `⟨1 + 2⟩` thunk. `foldl'` continues traversing the list in constant space, never building a thunk larger than a single application of `(+)`. ### `foldr`, lazily But what about `foldr`? Remember that in a strict language, `foldr` already needed to consume space linear in the size of the input list, since it fundamentally needed the last element in the list before it could start reducing. Indeed, if we consider a lazy `foldr` with a strict operation like `(+)`, this is still true—but in an interestingly _different_ way from `foldl`. With `foldl`, we ended up building thunks incrementally as we traversed the list, leading to a very large, nested thunk. But with `foldr`, that doesn’t actually happen. Why? Well, consider the expansion again for just a moment: foldr (+) 0 [1, 2, 3, 4] = 1 + (2 + (3 + (4 + 0))) To consider how we end up with this expansion, let’s write the expansion out in an explicitly inductive way: foldr (+) 0 [1, 2, 3, 4] = 1 + foldr (+) 0 [2, 3, 4] = 1 + (2 + foldr (+) 0 [3, 4]) = 1 + (2 + (3 + foldr (+) 0 [4])) = 1 + (2 + (3 + (4 + foldr (+) 0 []))) = 1 + (2 + (3 + (4 + 0))) This makes the recursive calls to `foldr` more explicit. In a strict language, as soon as we call `foldr`, we need to demand the result, so we _have_ to traverse the whole list. But here’s where things get interesting—in a lazy language, we can actually just return the following result, with a suspended thunk: foldr (+) 0 [1, 2, 3, 4] = 1 + ⟨foldr (+) 0 [2, 3, 4]⟩ This might seem totally irrelevant, since once that result is forced, the `⟨foldr (+) 0 [2, 3, 4]⟩` will be forced by `(+)`, and we’ll get the same reduction sequence we had before. But note that this is only true because `(+)` is a strict operation. What if we instead used a _lazy_ operation, like `(:)`? In that case, we’d get the following expansion: foldr (:) [] [1, 2, 3, 4] = 1 : ⟨foldr (:) [] [2, 3, 4]⟩ Guess what? That result is already in weak-head normal form (WHNF)! So evaluation just stops there until the rest of the result is explicitly demanded by something else. Now, in this case, this is a silly operation, since `foldr (:) []` is just a complicated identity function on lists, but we could imagine a slightly more complicated function, such as one that doubles each element in a list: let f x xs = (x * 2) : xs in foldr f [] [1, 2, 3, 4] This will expand into the following: foldr f [] [1, 2, 3, 4] = ⟨1 * 2⟩ : ⟨foldr f [] [2, 3, 4]⟩ …and again, it will just stop there, since it’s already in WHNF. How is this useful? Well, what if we didn’t actually consume the entire result list, like this? sum (take 2 (foldr f [] [1, 2, 3, 4])) Because `take 2` will only return the first two elements of the list, then when `sum` forces the list and its values to add them together, it will never even evaluate the thunk `⟨foldr f [] [3, 4]⟩`, and the list will only be partially-traversed. What are the implications of this? Well, it means that `foldr` can possibly save on work if the reducing function is lazy in its second argument, and the result list is not entirely consumed. In fact, **`foldr` can operate on infinite lists** this way, while `foldl` cannot. It also means that `foldr` may be subject to more list fusion than `foldl`, though that’s another discussion entirely. ### `foldl` vs. `foldr`, lazily Okay, so, to briefly recap, here’s what I’ve said so far: 1. In a lazy language, `foldl` on lists is bad because it’s too lazy, and it builds up big thunks. Use `foldl'` instead to force the thunks incrementally and consume the list in constant space. 2. In a lazy language, `foldr` on lists is good because it’s lazy, so if the reducing function is lazy in its second argument, it can save on work. These two things might seem a little contradictory. Why is `foldl` bad because it’s too lazy while `foldr` is good because it’s lazy? To understand the difference, let’s expand `foldl` inductively like we did with `foldr`: foldl (+) 0 [1, 2, 3, 4] = foldl (+) (0 + 1) [2, 3, 4] = foldl (+) ((0 + 1) + 2) [3, 4] = foldl (+) (((0 + 1) + 2) + 3) [4] = foldl (+) ((((0 + 1) + 2) + 3) + 4) [] = ((((0 + 1) + 2) + 3) + 4) See the difference? With `foldr`, the recursive call was pushed into a “leaf” of the resulting expression tree, but with `foldl`, the recursive call is always the root. This is, by the way, why `foldl` is tail recursive—this is exactly what tail recursion _is!_ —but it means it can’t possibly be lazy, since it will never be in WHNF until the entire list has been traversed. This gives us a general rule of thumb for using `foldl` and `foldr` on lists: 1. When the accumulation function is strict, use `foldl'` to consume the list in constant space, since the whole list is going to have to be traversed, anyway. 2. When the accumulation function is lazy in its second argument, use `foldr` to do work incrementally to improve streaming and work-saving. 3. Never use `foldl` or `foldr'`; they’re always worse on lists. In your case, the accumulation function you’re applying is `Map.delete`, which _is_ strict, so you should use `foldl'`. That said, this is often a micro-optimization, so if the list is not large, it usually doesn’t really matter. It’s just a good habit to get into, and it’s worth understanding, since it’s a great example of laziness in practice. ### Addendum: `foldl` and `foldr` on other data structures As a final note, you might wonder: if `foldl` and `foldr'` are so useless, why do they even exist? Why not just have `foldl'` and `foldr`? The answer is that everything I just said only applies to lists. This behavior happens because, fundamentally, `(:)` is a right-associative operation, so the “remainder” of the list is on the right. But if we had snoc lists, like this: data SnocList a = Nil | Snoc (SnocList a) a …then our lists would be _left-associative_ , and we’d want to use `foldr'` in situations where we use `foldl'` on ordinary lists and `foldl` where we use `foldr` on ordinary lists. A little confusing, isn’t it? Ordinary cons lists and snoc lists are basically the two extremes of `foldl` vs `foldr`, but in practice, other data structures are a lot fuzzier. For example, if you have a tree, like data Tree a = Leaf | Branch (Tree a) a (Tree a) …then some elements are on the left and others are on the right, and neither `foldl` nor `foldr` are clearly better. In that case, if you really, really care about performance, `foldMap` and `foldMap'` are usually your best bet, since they don’t specify any particular associativity of calls to `(<>)`. However, we don’t have `foldMap'` until `base-4.13.0.0`, which won’t be available until we switch to GHC 8.8.1. (But in truth, it probably doesn’t matter, anyway.)
blog.haskell.org
September 26, 2026 at 10:25 AM
foldl and foldr? No, fold and fnew
November 27, 2025 at 2:46 PM
just regular modules that contain code. if you want to find out which functions you can call on a list, you can write "List." and have it autocomplete to map, foldl, filterMap, etc.
December 9, 2024 at 10:58 PM
with builtins; foldl' (a: b: a + fromJSON "\"\\u00${b}\"") "" ["6E" "69" "78" "20" "77" "69" "74" "63" "68"] ~ thunder
dyslexic nix blue woozer aimbot ~ selfie
friendly funny nix witch I like and am fond of ~ diza!
level of nix knowledge scares me ~ toasitelad
August 12, 2025 at 8:45 PM
if you're wondering, btw: yes, I did it in the most complicated way possible

there's `apply`, there's `foldl`, there's `for`, and there's of course `for/sum`

the `for` iterators are Racket-specific and I think they're pretty: gay
March 22, 2026 at 1:14 PM
Foldr Foldl Foldl' - HaskellWiki
wiki.haskell.org
December 7, 2024 at 10:27 AM
you can do a foldl with a comprehension with the walrus operator but it's very cursed
May 2, 2025 at 3:11 PM
Untrue. It also justifies my salary when I replace foldl by foldl’, brag about it in company meeting, how I saved the day with an impressive optimisation, and justify the knowledge sharing session where I can explain the difference.
August 13, 2025 at 7:21 AM