alamba78

alamba78

What is the real-world use case for List Folding?

I’ve been reading “Introduction to Elixir” and I’m trying to understand where List.foldl and List.foldr would be useful. Basically, I’m looking for a use case. In what situation would the lightbulb go on that hey I should fold the list in this situation.

I believe List fold is very cheap to use (as long as it’s List.foldl as it’s tail recursive) but many people fail to understand a situation where it may be the tool for the job.

Thanks!

Most Liked

JEG2

JEG2

Author of Designing Elixir Systems with OTP

Well, you know all those iterators in Enum? The truth is that you could choose to handle most of that with fold*(). Here are examples for map(), sum(), and filter():

iex(1)> nums = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
iex(2)> List.foldr(nums, [ ], fn n, doubles -> [n * 2 | doubles] end)
[2, 4, 6, 8, 10]
iex(3)> List.foldl(nums, 0, fn n, sum -> n + sum end)
15
iex(4)> require Integer
nil
iex(5)> List.foldr(nums, [ ], fn n, evens -> if Integer.is_even(n), do: [n | evens], else: evens end)
[2, 4]
ejc123

ejc123

Here is an explanation of folds on lists: List Folds at BFPG
I only briefly read through the slides, so I can’t comment on the presentation, but I believe it should shed some light on the mystery of folds. Folds for Imperative Programmers is just what the title says. The code is in Scala, but it should be navigable.

I’ve read some of Tony’s other work and he knows his category theory concepts. His Monad Exercises in Scala (Haskell too) will change the way you think about programming.

NobbZ

NobbZ

I think that folds are best understood when source is provided.

Therefore I’ll do a quick translate of my haskell-lecture-notes to elixir
without taking optimisations into accont. I use my haskell notes since they are
(nearly) always around my desk :wink:

defmodule Folds do
  def foldl(list, fun, acc)
  def foldl([], _fun, acc), do: acc
  def foldl([x|xs], fun, acc), do: foldl(xs, fun, fun.(x, acc))
  
  def foldr(list, fun, acc)
  def foldr([], _fun, acc), do: acc
  def foldr([x|xs], fun, acc), do: fun.(x, foldr(xs, fun, acc))
end

Using these definitions, I will use each of the folds with 2 very simple
functions:

  1. foldr [1,2,3], &(&1 + &2), 0
  2. foldl [1,2,3], &(&1 + &2), 0
  3. foldr [1,2,3], &([&1|&2]), []
  4. foldl [1,2,3], &([&1|&2]), []
1. foldr [1,2,3], &(&1 + &2), 0
=> foldr [1|[2,3]], &(&1 + &2), 0
=> &(&1 + &2).(1, foldr([2,3], &(&1 + &2), 0))
=> &(&1 + &2).(1, foldr([2|[3]], &(&1 + &2), 0))
=> &(&1 + &2).(1, &(&1 + &2).(2, foldr([3], &(&1 + &2), 0)))
=> &(&1 + &2).(1, &(&1 + &2).(2, foldr([3|[]], &(&1 + &2), 0)))
=> &(&1 + &2).(1, &(&1 + &2).(2, &(&1 + &2).(3, foldr([], &(&1 + &2), 0))))
=> &(&1 + &2).(1, &(&1 + &2).(2, &(&1 + &2).(3, 0)))
=> &(&1 + &2).(1, &(&1 + &2).(2, 3 + 0))
=> &(&1 + &2).(1, &(&1 + &2).(2, 3))
=> &(&1 + &2).(1, 2 + 3)
=> &(&1 + &2).(1, 5)
=> 1 + 5
=> 6

2. foldl [1,2,3], &(&1 + &2), 0
=> foldl [1|[2,3]], &(&1 + &2), 0
=> foldl [2,3], &(&1 + &2), &(&1 + &2).(1, 0)
=> foldl [2,3], &(&1 + &2), 1 + 0
=> foldl [2|[3]], &(&1 + &2), 1
=> foldl [3], &(&1 + &2), &(&1 + &2).(2, 1)
=> foldl [3], &(&1 + &2), 2 + 1
=> foldl [3|[]], &(&1 + &2), 3
=> foldl [], &(&1 + &2), &(&1 + &2).(3, 3)
=> foldl [], &(&1 + &2), 3 + 3
=> foldl [], &(&1 + &2), 6
=> 6

3. foldr [1,2,3], &([&1|&2]), []
=> foldr [1|[2,3]], &([&1|&2]), []
=> &([&1|&2]).(1, foldr([2,3], &([&1|&2]), []))
=> &([&1|&2]).(1, foldr([2|[3]], &([&1|&2]), []))
=> &([&1|&2]).(1, &([&1|&2]).(2, foldr([3], &([&1|&2]), [])))
=> &([&1|&2]).(1, &([&1|&2]).(2, foldr([3|[]], &([&1|&2]), [])))
=> &([&1|&2]).(1, &([&1|&2]).(2, &([&1|&2]).(3, foldr([], &([&1|&2]), []))))
=> &([&1|&2]).(1, &([&1|&2]).(2, &([&1|&2]).(3, [])))
=> &([&1|&2]).(1, &([&1|&2]).(2, [3]))
=> &([&1|&2]).(1, [2,3])
=> [1,2,3]]

4. foldl [1,2,3], &([&1|&2]), []
=> foldl [1|[2,3]], &([&1|&2]), []
=> foldl [2,3], &([&1|&2]), &([&1|&2]).(1, [])
=> foldl [2,3], &([&1|&2]), [1]
=> foldl [2|[3]], &([&1|&2]), [1]
=> foldl [3], &([&1|&2]), &([&1|&2]).(2, [1])
=> foldl [3], &([&1|&2]), [2,1]
=> foldl [3|[]], &([&1|&2]), [2,1]
=> foldl [], &([&1|&2]), &([&1|&2]).(3, [2,1])
=> foldl [], &([&1|&2]), [3,2,1]
=> [3,2,1]

Personally I think, the best way to understand higher order functions, is just
to take a small example output, look at the definition and go through it by
hand. We had to do this a lot during FP exercises…

Pen and Paper, vim, emacs, whatever you like most, but beeing capable of
monospaced fonts helps a lot :wink:

edit
I’ve seen @alamba78’s latest reply to late, but I had not used that function anyway, since it produces improper lists!

Improper lists are something you want to avoid, that are lists, where the last “element” is not the empty list, but something else. They can really confuse your code. The example you are showing is even nesting them…

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> somethi...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

We're in Beta

About us Mission Statement