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. 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+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.