Looking back, I think having acc as the first argument would be have a
better choice. But we have other functions named after "fold" such as
List.foldl/3, List.foldr/3, Inspect.Algebra.fold_doc/2 that take a
function in the same format as Enum.reduce/3. So having some
fold functions that take a function in the (current_acc, element ->
updated_acc) format and others in the (element, current_acc ->
updated_acc) would be hard to remember which one is which. I guess this
proposal should consider a different name for the new function.

On Wed, 9 Dec 2020 09:40:35 -0500
Bruce Tate <br...@grox.io> wrote:

> This is a long post, and I think it might not be a popular one.
> Still, I think it has an important punchline, so bear with me.
> 
> Proposal: Add Enum.fold/2 and Enum.fold/3 (and the Stream
> counterparts). These both work like Enum.reduce, but flip the
> arguments in the reducer function.
> 
> As I teach and code Elixir, I have four steps for most students.
> First, we build common vocabulary and language constructs of Elixir.
> Next, we think in terms of a common pattern I call
> constructor-reducer-converter. (More in a sec.) Then, we apply that
> pattern in higher level constructs like LiveView and OTP. Finally, we
> build projects and let students code these patterns for themselves.
> In a phrase, *everything is reduce*. I want to focus on that second
> step.
> 
> I am thinking and teaching more about one common pattern. At its core,
> Elixir modules have functions around a common type T that either
> produce, transform, or consume T. I call these functions
> constructors, reducers, and converters. They all interact with type T.
> 
> Think of them in this way:
> 
> constructor(inputs) |> reducer(...) |> reducer(...) ... |> converter
> 
> This is the way the data-centric modules in Elixir are built today. In
> Designing Elixir Systems with OTP speak, they are the *core* modules,
> and I believe many Elixir developers build code this way, even if we
> don't vocalize it in this way.
> 
> Building code like this puts us in conflict in one important way:
> 
> 1. Elixir modules are generally organized around data of a common type
> (let's say T)
> 2. Named functions in a module have T as the first argument.
> 3. Pipes rely on T as a first argument.
> 4. In Enum.reduce, T is the accumulator, and it's the second argument
> of the reducer.
> 
> 3 and 4 are in conflict! The accumulator plays the role of T in the
> reducer:
> 
> reducer(any(), T) :: T
> 
> That's backwards, and it won't pipe.
> 
> If we have this:
> 
> 10 |> subtract(4) |> subtract(3)
> 
> and we want to express that code over a list that's arbitrarily long,
> we we must do this:
> 
> Enum.reduce([4, 3, ...], 10, fn x, acc -> subtract(acc, x) end)
> 
> to flip the two arguments to the correct place.
> 
> But we can't do so. I know the Elixir way is to generally put up with
> a little ceremony for the common good of a tighter standard library,
> most of the time, but I don't think this problem applies. I think
> that Elixir *wants* this function:
> 
> Enum.fold([4, 3], 10, &subtract2)
> 
> To me the cost is high:
> 
> 1. We must add a function to Enum, a central Elixir function
> 2. The function does almost the same thing as an existing function.
> 
> To me at least the benefit is higher:
> 
> Enum.fold encourages us to write better code in three ways:
> 
> A, Enum.fold encourages us to write code with T first, the Elixir way.
> 
> B, Enum.fold encourages named functions rather than anonymous
> functions which leads to more opportunities to name concepts without
> comments, always a good thing.
> 
> C. This strategy has a profound impact on tests of reducers, as we can
> simply pipe them and check the results.
> 
> What do you think?
> -bt
> 

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/5fd12f36.1c69fb81.6e0da.1dc6SMTPIN_ADDED_MISSING%40gmr-mx.google.com.

Reply via email to