Very true on the match inside `do/end`. Maybe controversial, but another potential idea would be to reduce the noise in the matches by supporting the js style object destructuring of `%{foo, bar}`. I can see how that is just a bit of a bandaid on top of the problem. I definitely see the problem statement here, but the proposal of the automatically tracked variables just seems difficult to swallow. It adds a whole new class of problem when working inside of loop bodies. If it would be added, I personally feel like a new designator like `$var` would actually be in order, so that someone doesn't refactor something without realizing they are actually affecting all other iterations. I'm definitely not in the camp of "we can do this with functions now, so lets not change anything". I often feel like comprehensions are just like 80% of the way to being a god-mode tool, so I'm all in favor of improving this aspect of it. I almost always choose functions + composition at the moment just because I know I won't end up limited/having to refactor it to the same degree as I might w/ a for comprehension now.
Sent via Superhuman ( https://sprh.mn/?vip=zachary.s.dan...@gmail.com ) On Fri, Dec 17, 2021 at 1:45 PM, 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. daniel@ gmail. com > ( 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. valim@ dashbit. co ( >> 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. daniel@ gmail. com >>> ( 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 < >>>> evangelistajoaop@ >>>> gmail. com ( 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 ( >>>>> 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 >>>>>>> ( 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+unsubscribe@ googlegroups. com ( >>>>> 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+unsubscribe@ googlegroups. com ( >>>> 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+unsubscribe@ googlegroups. com ( >>> 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+unsubscribe@ googlegroups. com ( >> 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+unsubscribe@ googlegroups. com ( > elixir-lang-core+unsubscr...@googlegroups.com ). > To view this discussion on the web visit https:/ / groups. google. com/ d/ > msgid/ elixir-lang-core/ > CAGnRm4KYCQC%2BYx8ibOW4Gbnbj7161BvvkbDSdE9oaV_zkUYhLw%40mail. > gmail. com ( > https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4KYCQC%2BYx8ibOW4Gbnbj7161BvvkbDSdE9oaV_zkUYhLw%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/kxaqt4i7.2c98da7f-92fb-43b0-ad54-bdce7f3baab5%40we.are.superhuman.com.