mszmurlo
Recently ‘discovered’ the reduce: option for comprehensions. Very useful, yet there is a syntax difference between into: and reduce: that I don’t understand:
-
into:requires the comprehension’s code block to return the element that is to be inserted into the collection:for x<-0..2, y<-0..3, into: %{} do {{x, y}, x*y} end -
reduce:requires aaccumulator -> codeblockfor x<-0..2, y<-0..3, reduce: %{} do acc -> acc |> Map.put({x, y}, x*y) endThis allows doing multiple modifications to the collections which actually was my use case:
for x<-0..2, y<-0..3, reduce: %{} do acc -> acc |> Map.put({x, y}, x*y) |> Map.put({x+10, y+10}, x*y) end
I was wondering why in the first case we simply return the element to be inserted while in the second case we need a acc -> code(acc) block. I believe it’s for having the possibility to name the accumulator, but is this assumption correct?
I could imagine that for into: we could return a tuple of all the inserts to be done:
for x<-0..2, y<-0..3, into: %{} do
{ {{x, y}, x*y}, {{x+10, y+10}, x*y} }
end
or for reduce: to have a syntax like reduce: {acc_name, acc_initial_value}:
for x<-0..2, y<-0..3, reduce: {acc, %{}} do
acc |> Map.put({x, y}, x*y) |> Map.put({x+10, y+10}, x*y)
end
(I actually never really thought about what acc -> some_code(acc) means. I simply use it because the documentations says so. So I may also need a quick explanation on this topic…)
Trending in Thoughts On...
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #ai
- #phoenix_html
- #iex
- #elixirconf-us
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 8- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
LostKobrakai
The reduce syntax mimics the syntax of an anonymous function
fn parameter -> body end. The reduce option uses that, because it‘s the only option onfor, which gets an extra input beyond what is provided by generators or assignments in thefor … doportion - the first parameter to theforspecial form.gregvaughn
Note, this is equivalent to
for x <- 0..2, y <- 0..3, z <- [0, 10], into: %{}, do: {{x+z, y+z}, x*y}If you have a single clause for your accumulator, then you can likely find a way to convert to an
intoinstead ofreduce. Wherereducereally shines is when you choose not to update the accumulator under some conditions. This implies multiple clauses. (And even some of those could use the filter feature offorbut not many people are familiar or comfortable withforfilters).mudasobwa
Well, I am the one who uses
forcomprehension if and only if I need a filter (maybe several nested clauses as well, but I don’t realy do numeric calculus often.) Specifically, I love filtering with pattern matching, not the barex < 0-like filters:YMMV.
mudasobwa
This question is isomorphic to the following one:
One might abuse
Enum.reduce/3for mapping, but the actual difference is reduce is folding, decreasing the dimension of the input. In SQL that’s called aggregation.sumis arguably the most trivial example, receiving a list and producing a scalar. That’s obviously impossible without the accumulator.gregvaughn
Oh, but we do have
The first element of the enumerable is the initial accumulator which is only useful if your result is the same type as the elements of the enumerable, which arguably makes 
Enum.reduce/2alsosumthe poster child forEnum.reduce/2mudasobwa
Technically, we don’t. It’s just a syntactic sugar. But yes, I get your point
codeanpeace
That’s how I think of it as well which reflects why it’s named “reduce”
Funnily enough though, OP’s example is using
reduceto unfold and increase the dimension so whereas mapping is n to n, reducing is n to any though typically less than n ¯\_(ツ)_/¯josevalim
Simplest way to think about it is that :into is a convenient option that builds on top of reduce. You give it a data type and Elixir adds the reduce loop associated to that data structure for you (which is done via the collectable protocol).