<div dir="ltr">The problem with suggesting developers use existing abstractions or make their own is that it can (in some circumstances) result in rather verbose, hard to read code. foldl is particularly hostile to state variables (which I use a lot).<div>

<br></div><div>As I see it, there are two "inconveniences" with using foldl in place of dedicated for loop syntax:</div>

<div><ol><li>The need to explicitly define a predicate and the rather awkward syntax of doing it in-line, as well as having to a) explicitly list both the input and output of each state variable, and b) explicitly list the modes of all parameters and the predicate itself.</li>

<li>The fact that you must place the input list and variables to be updated at the end of the "loop body", making it hard to read what is going on until you reach the end.</li></ol><div>To illustrate these points, consider a function that takes an assoc_list of name-value pairs and prints them out neatly:</div>

<div><br></div><div><div>:- pred print_key_values(assoc_list(string, string)::in, io::di, io::uo) is det.</div><div>print_key_values(List, !IO) :-</div><div>    list.foldl((pred(X-Y::in, !.IO::di, !:IO::uo) is det :-</div>


<div>        io.write_string(X, !IO),</div><div>        io.write_string(" = ", !IO),</div><div>        io.write_string(Y, !IO),</div><div>        <a href="http://io.nl">io.nl</a>(!IO)</div><div>    ), List, !IO).</div>


</div><div><br></div><div>There is no need to define a "print_key_value_pair" predicate since I only need it in this one spot, so I use a lambda predicate. To Point 1, note how awkward it is to place the predicate inline, requiring extra parens around the predicate. I need to explicitly mention !.IO and !:IO (in addition to mentioning that I am passing !IO at the end), and I need to explicitly list the modes of the parameters and the determinism of the predicate. Being explicit about all this is fine when writing a separate predicate, but here I am really just trying to iterate over a list and do something with each element. I should not have to care about modes or determinism at this point. To Point 2, note that you can't see which list I am iterating over, nor which state variable I am updating, until the very end. There is also no strong visual association that says "X-Y is an element of List" (unlike, say Python, where you would just write "for (X, Y) in List").</div>

<div><br></div><div>I would propose a for loop syntax for Mercury which can be used something like this:</div><div><br></div><div><div>:- pred print_key_values(assoc_list(string, string)::in, io::di, io::uo) is det.</div>

<div>print_key_values(List, !IO) :-</div><div>    for X-Y in List [!IO] (</div><div>        io.write_string(X, !IO),<br></div><div>        io.write_string(" = ", !IO),</div><div>        io.write_string(Y, !IO),</div>

<div>        <a href="http://io.nl">io.nl</a>(!IO)</div><div>    ).</div></div><div><br></div><div>The features of this syntax are:</div><div><ol><li>Clearly shows that X-Y is the elements of List, and that List is the list being iterated over.</li>

<li>Only need to specify the accumulators once (!IO), instead of specifying them both in the predicate head and as separate arguments.</li><li>Works naturally with the !S state variable notation, not requiring the user to break the illusion of S being a single variable and specify !.S and !:S.</li>

<li>Does not allow the "invention" of new accumulator names; instead, you are merely specifying existing variables from the outer scope (typically state variables) that may be updated in the body of the loop.</li>

<li>Does not require the user to have to decide whether to use foldl, foldl2, foldl3, etc. It works for any number of accumulator variables.</li><li>It keeps the idea that the user must explicitly specify which variables can be updated by the loop body. You can't just go updating any state variable in the outer scope, for example.</li>

</ol></div><div>This is intended to be a syntactic sugar around list.foldl:</div><div><br></div><div>for <i>element</i> in <i>iterable</i> [<i>accumulators</i>] (<i>body</i>)</div><div><br></div><div>Where <i>element</i> is a term of type T, <i>iterable</i> is a term of type list(T), <i>accumulators</i> is a list of variable names of even length (where a state variable counts as both the !. and !: variable), and <i>body</i> is a goal.</div>

<div><br></div><div>This expands to:</div><div><br></div><div>list.foldl<i>n</i>((pred(<i>element</i>::in, <i>accumulator1</i>::<i>accumulator1_mode</i>, ..., <i>accumulatorn</i>::<i>accumulatorn_mode</i>) is det :- <i>body</i>),</div>

<div>    <i>iterable</i>, <i>accumulator1</i>, ..., <i>accumulatorn</i>).</div><div><br></div><div>Note that the expansion needs to work out the correctly numbered version of foldl, as well as the mode of each accumulator variable.</div>

<div><br></div><div>It doesn't explicitly require state variables; you could just pass two or more normal variables as accumulators, but it would usually be used with state variables. I'm sure this could be generalized better (for example, allowing it to expand to use any of the many permutations of map, fold, filter, etc, as Peter hinted at). Another nice generalization would be if it worked on any iterable object, not just lists. For example, if it could work out that if <i>iterable</i> is a map, it should call <i>map.foldl</i>. That could be done by introducing a type class <i>iterable</i> which provides a foldl method, or even a full-blown iterator implementation, and then having the for syntax expand to that. But this is just a quick proposal, not intended to be taken too seriously.</div>

<div><br></div><div>Now having said all of this, I agree with some of the sentiments expressed above that such a feature does not "feel" like it belongs in Mercury. I wouldn't be surprised if this was deemed "un-Mercurial" for being too imperative. But I'm just saying that I would have found it useful all over the place (which perhaps speaks more about the way I think when I write code -- imperatively). And it does kind of fit with the existing state variable notation, as well as some of the existing quantifying goals like 'some'.</div>



</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Jan 2, 2014 at 10:09 PM, Paul Bone <span dir="ltr"><<a href="mailto:paul@bone.id.au" target="_blank">paul@bone.id.au</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Thu, Jan 02, 2014 at 07:30:18PM +1100, Julien Fischer wrote:<br>
> On Thu, Jan 2, 2014 at 7:26 PM, Paul Bone <<a href="mailto:paul@bone.id.au">paul@bone.id.au</a>> wrote:<br>
><br>
> > On Thu, Jan 02, 2014 at 06:20:27PM +1100, Julien Fischer wrote:<br>
> > > On Thu, Jan 2, 2014 at 5:50 PM, Michael Day <<a href="mailto:mikeday@yeslogic.com">mikeday@yeslogic.com</a>><br>
> > wrote:<br>
> > ><br>
> > > > Hi Paul,<br>
> > > ><br>
> > > ><br>
> > > >  foreach I=std::fromTo(1,1000) do<br>
> > > >>>     %...whatever<br>
> > > >>> end foreach.<br>
> > > >>><br>
> > > >><br>
> > > >> I think that such a feature would be considered "not in the spirit of<br>
> > > >> Mercury" by most developers.<br>
> > > >><br>
> > > ><br>
> > > > Light syntax and efficient compilation for lambdas is enough:<br>
> > > ><br>
> > > >     foreach(1 `..` 100, func(X) = blah)<br>
> > ><br>
> > ><br>
> > > Which is pretty much already supported, e.g.<br>
> > ><br>
> > >       map(func(X) = X * 2, 1 `..` 100)<br>
> > ><br>
> > > (Use a quantifier like foreach seems like the wrong name to use<br>
> > > for some that is transform the list of integers using a function.)<br>
> ><br>
> > foreach would be a predicate that is very similar to list.foldl.<br>
> ><br>
><br>
> It wouldn't, you would need to provide the initial value of the accumulator<br>
> somewhere.  In any case, my point was that foreach is not a good name<br>
> for such a thing.<br>
<br>
</div></div>We do that in list.foldl as a parameter.  I don't see why it should be any<br>
different.  Anyway, I'm not saying that Mercury should add foreach anywhere.<br>
I'm saying that anyone who wants to create loops can write a wrapper around<br>
foldl or anything else to create the abstractions they want.  Or just use<br>
foldl because it is already such an abstraction.<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
--<br>
Paul Bone<br>
<a href="http://www.bone.id.au" target="_blank">http://www.bone.id.au</a><br>
_______________________________________________<br>
developers mailing list<br>
<a href="mailto:developers@lists.mercurylang.org">developers@lists.mercurylang.org</a><br>
<a href="http://lists.mercurylang.org/listinfo/developers" target="_blank">http://lists.mercurylang.org/listinfo/developers</a><br>
</div></div></blockquote></div><br></div>