Apologies, I re-read my first reply to you and it was definitely not clear I was taking about both approaches.
On Fri, Dec 17, 2021 at 19:45 José Valim <jose.va...@dashbit.co> wrote: > That’s what I meant. The reduce solution requires the reverse. The state > proposal is very close to the Enum.map_reduce/3 solution, as it keeps all > of its noise in passing the accumulator, matching on it, and returning it. > > I am sure it is clear for an Elixir developer but so is Enum.map_reduce/3. > Can we find a point midway? Maybe yes, maybe no. :) > > PS: And, although we got used with for+:reduce, we have to admit that the > fact the accumulator is matched in a clause inside do-end is a specific > behavior to for that we partly accept because we got used to it! > > On Fri, Dec 17, 2021 at 19:19 Zach Daniel <zachary.s.dan...@gmail.com> > wrote: > >> The first approach I described was just me confirming my understanding of >> a corollary of the desired behavior that we can do now. The original >> problem stated using the method I showed in my second example would look >> like this, which seems pretty clean to me. >> >> ``` >> section_counter = 1 >> lesson_counter = 1 >> >> {sections, _} = >> for section <- sections, >> state: %{section_counter: section_counter, lesson_counter: >> lesson_counter} do >> %{lesson_counter: lesson_counter, section_counter: section_counter} -> >> lesson_counter = if section["reset_lesson_position"], do: 1, else: >> lesson_counter >> >> {lessons, lesson_counter} = >> for lesson <- section["lessons"], state: lesson_counter do >> lesson_counter -> >> lesson = Map.put(lesson, "position", lesson_counter) >> {lesson, lesson_counter + 1} >> end >> >> section = >> section >> |> Map.put("lessons", lessons) >> |> Map.put("position", section_counter) >> >> {section, %{section_counter: section_counter + 1, lesson_counter: >> lesson_counter}} >> end >> ``` >> Although I did originally forget to include the fact that if `state` is >> specified then not only do you match on it and return a tuple, but that the >> comprehension would return a tuple as well. >> >> Sent via Superhuman <https://sprh.mn/?vip=zachary.s.dan...@gmail.com> >> >> >> On Fri, Dec 17, 2021 at 1:04 PM, José Valim <jose.va...@dashbit.co> >> wrote: >> >>> Hi Zach, >>> >>> I recommend trying out your approach on the original problem. You will >>> see that you will need to accumulate elements, add Enum.reverse/1, etc. All >>> which will make the solution noisier. >>> >>> On Fri, Dec 17, 2021 at 6:59 PM Zach Daniel <zachary.s.dan...@gmail.com> >>> wrote: >>> >>>> I may not fully be understanding what we're looking for here, but it >>>> seems like this would effectively be the equivalent of: >>>> >>>> ``` >>>> result = >>>> for foo ← [1, 2, 3], reduce: %{acc: [], counter: 0} do >>>> %{acc: acc, counter: counter} -> >>>> new_acc = some_calc(acc) >>>> %{acc: new_acc, counter: counter + 1} >>>> end >>>> >>>> actual_result = result.acc >>>> ``` >>>> >>>> I'm wondering if we could just introduce an additional `state` that you >>>> match on, and return as a tuple from the for loop body? I think this is >>>> similar to what the original proposal wanted, but it involves only knowing >>>> that if you use the `state` option, you need to return a tuple of the for >>>> loop result and the new state. And it looks similar to a genserver in that >>>> regard, which makes it feel reasonably conventional. >>>> >>>> ``` >>>> result = >>>> for foo ← [1, 2, 3], reduce: [], state: %{counter: 0} do >>>> acc, state → >>>> {some_calc(acc, state.counter), %{state | counter: state.counter + >>>> 1}} >>>> end >>>> ``` >>>> >>>> >>>> Sent via Superhuman <https://sprh.mn/?vip=zachary.s.dan...@gmail.com> >>>> >>>> >>>> On Fri, Dec 17, 2021 at 10:35 AM, João Pedro Evangelista < >>>> evangelistajo...@gmail.com> wrote: >>>> >>>>> *> In fact, making special-semantics different syntactically to be >>>>> more googleable * >>>>> >>>>> Also more easily scannable while reading the code, we would know that >>>>> this variable has more meaning among the other ones >>>>> On Friday, December 17, 2021 at 9:32:18 AM UTC-3 christ...@gmail.com >>>>> wrote: >>>>> >>>>>> *> I did consider introducing (precisely) $ for variables but my >>>>>> concern is that, by introducing special syntax, I believe most would >>>>>> expect >>>>>> it to be fully mutable, so you can modify it from any scope.* >>>>>> >>>>>> I am not sure if I can envision a way to allow imperative-ish >>>>>> variables without introducing special semantics. So I feel like >>>>>> supporting >>>>>> the new semantics with special syntax would allow us to set correct >>>>>> expectations about its scope and mutability when introducing/documenting >>>>>> it! >>>>>> >>>>>> In fact, making special-semantics different syntactically to be more >>>>>> googleable is a perk over plain variables in my mind. For example, >>>>>> searching *"ruby double at"* (a comparatively oblique ruby language >>>>>> identifier feature, *@@class_variables*), returns an appropriate top >>>>>> result >>>>>> <https://stackoverflow.com/questions/5890118/what-does-variable-mean-in-ruby> >>>>>> (from an incognito browser session, no less)! So maybe an *"elixir >>>>>> dollar variable" * google search is a reasonable standard to hold >>>>>> ourselves to. >>>>>> >>>>>> On Friday, December 17, 2021 at 5:40:14 AM UTC-5 sabi...@gmail.com >>>>>> wrote: >>>>>> >>>>>>> Indeed this doesn't address the issue of the level of nesting, and >>>>>>> is confusing in this case. >>>>>>> >>>>>>> The new syntax could maybe include the level of nesting information >>>>>>> somehow, e,g. `* $section_counter*` in the parent loop, `* >>>>>>> $$section_counter*` in the child loop...? >>>>>>> Or *$1.section_counter = 1 *(parent),* $2.section_counter = 1 * >>>>>>> (child)? (slightly inspired by &1) >>>>>>> *.* >>>>>>> >>>>>>> Another way to deal with this inconsistency could be to forbid >>>>>>> nested comprehension with variables, and require to extract as a new >>>>>>> function (in the same way the & cannot be nested and require to use fn). >>>>>>> Most examples would probably be easier to understand this way >>>>>>> anyway, but this might limit the power of the feature. >>>>>>> >>>>>>> Or maybe just having the compiler raising an error if trying to >>>>>>> re-assign within a nested block, with a helpful beginner-friendly >>>>>>> message, >>>>>>> could be enough to clear this confusion? >>>>>>> I think this is not so much harder to figure than the fact than a >>>>>>> re-assignment within an *if* doesn't work as in imperative >>>>>>> languages. >>>>>>> >>>>>>> By looking at the examples here, I feel that the last one might be >>>>>>> the most elegant of these 3 ideas: >>>>>>> https://gist.github.com/sabiwara/97c480c2076666ba9b98cf7a142a5a0f >>>>>>> >>>>>>> >>>>>>> Le ven. 17 déc. 2021 à 16:14, José Valim <jose....@dashbit.co> a >>>>>>> écrit : >>>>>>> >>>>>>>> *Re: for section <- sections, $section_counter = 1, $lesson_counter >>>>>>>> = 1 do* >>>>>>>> >>>>>>>> I did consider introducing (precisely) $ for variables but my >>>>>>>> concern is that, by introducing special syntax, I believe most would >>>>>>>> expect >>>>>>>> it to be fully mutable, so you can modify it from any scope. That's >>>>>>>> why I decided to go with plain variables, because they already have a >>>>>>>> limited scope in Elixir and clear rules (but at the same time I agree >>>>>>>> that >>>>>>>> adding :let would make those clear rules precisely more confusing!). >>>>>>>> >>>>>>>> On Fri, Dec 17, 2021 at 7:01 AM Christopher Keele < >>>>>>>> christ...@gmail.com> wrote: >>>>>>>> >>>>>>>>> I love the thought put into this proposal, and really like the >>>>>>>>> problem it is tackling! I am looking forward to the next proposal and >>>>>>>>> will >>>>>>>>> try to get to my inbox earlier for it. >>>>>>>>> >>>>>>>>> *Proposal Feedback* >>>>>>>>> >>>>>>>>> I mostly second the impressions voiced here, but *really* want to >>>>>>>>> call attention to the criticism: >>>>>>>>> >>>>>>>>> *> this breaks refactoring for the inner contents of `for`* >>>>>>>>> >>>>>>>>> This is the real true deal-breaker for me. Referential >>>>>>>>> transparency is a huge part of my mental model of Elixir and the key >>>>>>>>> reason >>>>>>>>> why it is such a joy to maintain code in. I am not sure if it is >>>>>>>>> possible >>>>>>>>> to introduce an imperative-loop construct that *doesn't* violate >>>>>>>>> this property, so I may have to get over that. I do remember how >>>>>>>>> painful it >>>>>>>>> was to remove assignment-inside-ifs, though. >>>>>>>>> >>>>>>>>> *Replies* >>>>>>>>> >>>>>>>>> *Re: **for section <- sections, $section_counter = 1, >>>>>>>>> $lesson_counter = 1 do* >>>>>>>>> >>>>>>>>> *> Maybe a possibility could be to distinguish comprehension >>>>>>>>> variables, for example by prefixing them in the same way as module >>>>>>>>> attributes are prefixed with `@`.* >>>>>>>>> >>>>>>>>> This does elegantly solve my refactoring concern; in that >>>>>>>>> "imperative" comprehension variables copied out of the comprehension >>>>>>>>> could >>>>>>>>> immediately raise a syntax error, as would moving them into a >>>>>>>>> different >>>>>>>>> comprehension that does not have them declared as imperative in the >>>>>>>>> comprehension head. The compiler would also have to enforce never >>>>>>>>> letting >>>>>>>>> you use the same name with an imperative variables as with a normal >>>>>>>>> one, to >>>>>>>>> completely eliminate edge cases. I think this solution even works for >>>>>>>>> nested comprehensions, though I still am not sure how *that* >>>>>>>>> would work with the existing proposal. >>>>>>>>> >>>>>>>>> *> We could maybe even remove the `let` keyword altogether?* >>>>>>>>> >>>>>>>>> *That * makes me really like syntax. We are not exactly running >>>>>>>>> short on propositions but it nice to keep that overhead low. Also, >>>>>>>>> the only >>>>>>>>> other existing identifier syntax (module attributes) use a >>>>>>>>> prefix/sigil >>>>>>>>> approach as well, and this feels in the same category to me: we are >>>>>>>>> introducing a different type of identifier with different scoping >>>>>>>>> rules >>>>>>>>> (even though what happens at compile time to it is wildly different). >>>>>>>>> >>>>>>>>> *Re: **overloading the **<- operator* >>>>>>>>> >>>>>>>>> *> My concern about this is that `<-` in for means extracting >>>>>>>>> something from the collection, so giving it another meaning inside an >>>>>>>>> option can be quite confusing.* >>>>>>>>> >>>>>>>>> *> If I'm not mistaken it actually means pulling the next item >>>>>>>>> from an enumerable.* >>>>>>>>> >>>>>>>>> FWIW I've been writing Elixir for years and I still forget when I >>>>>>>>> crack open a *for* or for a *with* that I need to be using *<-* . >>>>>>>>> I've just internalized it as the "powerful SpecialForms clause >>>>>>>>> operator". >>>>>>>>> So I don't think allowing its use in other powerful new constructs, >>>>>>>>> potentially nested in *for* or *with*, or inside their options >>>>>>>>> lists, would be confusing, from my perspective at least. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> 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-co...@googlegroups.com. >>>>>>>>> To view this discussion on the web visit >>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/72ee4929-efde-476e-9124-bacd7460c486n%40googlegroups.com >>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/72ee4929-efde-476e-9124-bacd7460c486n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>> . >>>>>>>>> >>>>>>>> -- >>>>>>>> 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-co...@googlegroups.com. >>>>>>>> >>>>>>> To view this discussion on the web visit >>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2BsbvBxoj1mECXzBna%3DJE-R8%2Bj-CBuRZvgAf%2BsLp2aMjw%40mail.gmail.com >>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2BsbvBxoj1mECXzBna%3DJE-R8%2Bj-CBuRZvgAf%2BsLp2aMjw%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>>>>>> . >>>>>>>> >>>>>>> -- >>>>> 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/10d18915-55da-4b52-8e12-0992625039e3n%40googlegroups.com >>>>> <https://groups.google.com/d/msgid/elixir-lang-core/10d18915-55da-4b52-8e12-0992625039e3n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>> . >>>>> >>>> >>>> -- >>>> 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/kxaott2e.e380bedb-a7bd-4f10-8d2c-573d453c6880%40we.are.superhuman.com >>>> <https://groups.google.com/d/msgid/elixir-lang-core/kxaott2e.e380bedb-a7bd-4f10-8d2c-573d453c6880%40we.are.superhuman.com?utm_medium=email&utm_source=footer> >>>> . >>> >>> >>>> -- >>> 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/CAGnRm4KYBajtuG0sAA%2BOtaWDo8AKn5csz6irK3f-Y1BLmrqvbw%40mail.gmail.com >>> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4KYBajtuG0sAA%2BOtaWDo8AKn5csz6irK3f-Y1BLmrqvbw%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> . >>> >> >> -- >> 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/kxaprh1k.8bfd20dc-9ccf-46d7-b01a-9746ae11d488%40we.are.superhuman.com >> <https://groups.google.com/d/msgid/elixir-lang-core/kxaprh1k.8bfd20dc-9ccf-46d7-b01a-9746ae11d488%40we.are.superhuman.com?utm_medium=email&utm_source=footer> >> . >> > -- 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/CAGnRm4J76nw50ZdK2qShwgP0sdxehJCnjA6_giJLsR1OuFqZjA%40mail.gmail.com.