www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - feature request: N-ary map

reply Timothee Cour <thelastmammoth gmail.com> writes:
--047d7b33d75856086804dfb1d2bc
Content-Type: text/plain; charset=ISO-8859-1

I'd like to support N-ary map, ie std.algorithm.map that takes 1 or more
ranges as arguments and operates lazily on those.

example: suppose we have a 2 argument function, eg : auto absDiff(a,b){...}
before:
  zip(a,b).map!(u=>absDiff(u[0],u[1])).reduce!fun;
after:
  map!absDiff(a,b).reduce!fun;

currently the signature of std.algorithm.map is:
auto map(Range)(Range r) if (isInputRange!(Unqual!Range));
new signature:
auto map(Range...)(Range r) if (Range.length>0 &&
allSatisfy!(isInputRange!Unqual,Range));

implementation:
it can be implemented using zip and expand, but there is room for more
optimization potentially. Or will LDC/GDC be smart enough to have zero
overhead when using zip?

advantages:
concise and natural syntax
reduces need for zip, and adds optimization opportunities
reduces need for using foreach when zip is too confusing
no code breakage

--047d7b33d75856086804dfb1d2bc
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div><div>I&#39;d like to support N-ary map, ie std.algorithm.map that take=
s 1 or more ranges as arguments and operates lazily on those.</div><div><br=
</div><div>example: suppose we have a 2 argument function, eg : auto absDi=

<div>before:</div><div><div>=A0 zip(a,b).map!(u=3D&gt;absDiff(u[0],u[1])).r= educe!fun;</div><div>after:</div><div></div><div>=A0 map!absDiff(a,b).reduc= e!fun;</div></div><div><br></div><div>currently the signature of std.algori= thm.map is:</div> <div>auto map(Range)(Range r) if (isInputRange!(Unqual!Range));</div></div>= <div>new signature:</div><div>auto map(Range...)(Range r) if (Range.length&= gt;0 &amp;&amp; allSatisfy!(isInputRange!Unqual,Range));</div><div><br> </div><div>implementation:</div><div>it can be implemented using zip and ex= pand, but there is room for more optimization potentially. Or will LDC/GDC = be smart enough to have zero overhead when using zip?</div><div><br></div> <div>advantages:</div><div>concise and natural syntax</div><div>reduces nee= d for zip, and adds optimization opportunities</div><div>reduces need for u= sing foreach when zip is too confusing</div><div><div>no code breakage</div=

--047d7b33d75856086804dfb1d2bc--
Jun 21 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/21/13 3:45 PM, Timothee Cour wrote:
 I'd like to support N-ary map, ie std.algorithm.map that takes 1 or more
 ranges as arguments and operates lazily on those.

Actually map used to do that in its early days. Then I figured composing with chain() is even better. chain(r1, r2, r3).map... Andrei
Jun 21 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:
 On 6/21/13 3:45 PM, Timothee Cour wrote:
 I'd like to support N-ary map, ie std.algorithm.map that takes 1 or more
 ranges as arguments and operates lazily on those.

Actually map used to do that in its early days. Then I figured composing with chain() is even better. chain(r1, r2, r3).map... Andrei

Wait, I think I misunderstood... Andrei
Jun 21 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/21/2013 03:57 PM, Diggory wrote:
 On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu wrote:
 On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:
 On 6/21/13 3:45 PM, Timothee Cour wrote:
 I'd like to support N-ary map, ie std.algorithm.map that takes 1 or
 more
 ranges as arguments and operates lazily on those.




 You can use "zip" from std.range.

Timothee specifically said that he is trying to avoid zip: :)
 before:
   zip(a,b).map!(u=>absDiff(u[0],u[1])).reduce!fun;
 after:
   map!absDiff(a,b).reduce!fun;

Ali
Jun 21 2013
prev sibling next sibling parent "Diggory" <diggsey googlemail.com> writes:
On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu 
wrote:
 On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:
 On 6/21/13 3:45 PM, Timothee Cour wrote:
 I'd like to support N-ary map, ie std.algorithm.map that 
 takes 1 or more
 ranges as arguments and operates lazily on those.

Actually map used to do that in its early days. Then I figured composing with chain() is even better. chain(r1, r2, r3).map... Andrei

Wait, I think I misunderstood... Andrei

You can use "zip" from std.range.
Jun 21 2013
prev sibling next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
--089e013cc39681b4f404dfb21614
Content-Type: text/plain; charset=ISO-8859-1

On Fri, Jun 21, 2013 at 3:57 PM, Diggory <diggsey googlemail.com> wrote:

 On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu wrote:

 On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:

 On 6/21/13 3:45 PM, Timothee Cour wrote:

 I'd like to support N-ary map, ie std.algorithm.map that takes 1 or more
 ranges as arguments and operates lazily on those.

Actually map used to do that in its early days. Then I figured composing with chain() is even better. chain(r1, r2, r3).map... Andrei

Wait, I think I misunderstood... Andrei

You can use "zip" from std.range.

I know, please re-read the original post: before: zip(a,b).map!(u=>absDiff(u[0],u[1])).reduce!fun; after: map!absDiff(a,b).reduce!fun; --089e013cc39681b4f404dfb21614 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <br><br><div class=3D"gmail_quote">On Fri, Jun 21, 2013 at 3:57 PM, Diggory= <span dir=3D"ltr">&lt;<a href=3D"mailto:diggsey googlemail.com" target=3D"= _blank">diggsey googlemail.com</a>&gt;</span> wrote:<br><blockquote class= =3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd= ing-left:1ex"> <div class=3D"HOEnZb"><div class=3D"h5">On Friday, 21 June 2013 at 22:56:04= UTC, Andrei Alexandrescu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On 6/21/13 3:45 PM, Timothee Cour wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> I&#39;d like to support N-ary map, ie std.algorithm.map that takes 1 or mor= e<br> ranges as arguments and operates lazily on those.<br> </blockquote> <br> Actually map used to do that in its early days. Then I figured composing<br=

<br> chain(r1, r2, r3).map...<br> <br> Andrei<br> </blockquote> <br> Wait, I think I misunderstood...<br> <br> Andrei<br> </blockquote> <br></div></div> You can use &quot;zip&quot; from std.range.<br> </blockquote></div><br><div>I know, please re-read the original post:</div>= <div><div style=3D"color:rgb(34,34,34);font-family:arial,sans-serif;font-si= ze:13px;background-color:rgb(255,255,255)"><br></div><div style=3D"color:rg= b(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rg= b(255,255,255)"> before:</div><div style=3D"color:rgb(34,34,34);font-family:arial,sans-serif= ;font-size:13px;background-color:rgb(255,255,255)"><div>=A0 zip(a,b).map!(u= =3D&gt;absDiff(u[0],u[1])).reduce!fun;</div><div>after:</div><div></div><di= v> =A0 map!absDiff(a,b).reduce!fun;</div><div><br></div></div></div><div><br><= /div><div><br></div> --089e013cc39681b4f404dfb21614--
Jun 21 2013
prev sibling next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
--001a11c2e352132c5704dfb23921
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Fri, Jun 21, 2013 at 4:02 PM, Ali =C7ehreli <acehreli yahoo.com> wrote:

 On 06/21/2013 03:57 PM, Diggory wrote:

 On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu wrote:

 On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:

 On 6/21/13 3:45 PM, Timothee Cour wrote:

 I'd like to support N-ary map, ie std.algorithm.map that takes 1 or
 more
 ranges as arguments and operates lazily on those.





Timothee specifically said that he is trying to avoid zip: :)
 before:
   zip(a,b).map!(u=3D>absDiff(u[0],**u[1])).reduce!fun;
 after:
   map!absDiff(a,b).reduce!fun;

Ali

also works great with string lambdas: eg: dotproduct: before: zip(u,v).map!"a[0]*a[1]".reduce!"a+b"; after: map!"a*b"(u,v).reduce!"a+b"; =3D> clearer, and provides more room for optimizaton --001a11c2e352132c5704dfb23921 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Fri, Jun 21, 2013 at 4:02 PM, Ali =C7ehreli <span dir=3D"ltr">&lt;<a hre= f=3D"mailto:acehreli yahoo.com" target=3D"_blank">acehreli yahoo.com</a>&gt= ;</span> wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_qu= ote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex= "> <div class=3D"im">On 06/21/2013 03:57 PM, Diggory wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On 6/21/13 3:45 PM, Timothee Cour wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> I&#39;d like to support N-ary map, ie std.algorithm.map that takes 1 or<br> more<br> ranges as arguments and operates lazily on those.<br> </blockquote></blockquote></blockquote></blockquote> <br> </div><div class=3D"im"><blockquote class=3D"gmail_quote" style=3D"margin:0= 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> You can use &quot;zip&quot; from std.range.<br> </blockquote> <br></div> Timothee specifically said that he is trying to avoid zip: :)<div class=3D"= HOEnZb"><div class=3D"h5"><br> <br> &gt; before:<br> &gt; =A0 zip(a,b).map!(u=3D&gt;absDiff(u[0],<u></u>u[1])).reduce!fun;<br> &gt; after:<br> &gt; =A0 map!absDiff(a,b).reduce!fun;<br> <br></div></div><span class=3D"HOEnZb"><font color=3D"#888888"> Ali<br> </font></span></blockquote></div><br><div>also works great with string lamb= das:</div><div>eg: dotproduct:</div><div><br></div><div>before:<br>=A0 zip(= u,v).map!&quot;a[0]*a[1]&quot;.reduce!&quot;a+b&quot;;<br>after:<br>=A0 map= !&quot;a*b&quot;(u,v).reduce!&quot;a+b&quot;;</div> <div><br></div><div>=3D&gt; clearer, and provides more room for optimizaton= </div><div><br></div> --001a11c2e352132c5704dfb23921--
Jun 21 2013
prev sibling next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
--047d7b33d758e5a50404dfb2f61f
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Fri, Jun 21, 2013 at 4:14 PM, Timothee Cour <thelastmammoth gmail.com>wr=
ote:

 On Fri, Jun 21, 2013 at 4:02 PM, Ali =C7ehreli <acehreli yahoo.com> wrote=

 On 06/21/2013 03:57 PM, Diggory wrote:

 On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu wrote:

 On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:

 On 6/21/13 3:45 PM, Timothee Cour wrote:

 I'd like to support N-ary map, ie std.algorithm.map that takes 1 or
 more
 ranges as arguments and operates lazily on those.





Timothee specifically said that he is trying to avoid zip: :)
 before:
   zip(a,b).map!(u=3D>absDiff(u[0],**u[1])).reduce!fun;
 after:
   map!absDiff(a,b).reduce!fun;

Ali

also works great with string lambdas: eg: dotproduct: before: zip(u,v).map!"a[0]*a[1]".reduce!"a+b"; after: map!"a*b"(u,v).reduce!"a+b"; =3D> clearer, and provides more room for optimizaton

actually the version without the proposed N-ary map is even worse, because zip uses StoppingPolicy.shortest by default (which i find weird and contrary to D's safe by default stance): here's the (corrected) dotproduct: before: zip(StoppingPolicy.requireSameLength,u,v).map!"a[0]*a[1]".reduce!"a+b"; after: map!"a*b"(u,v).reduce!"a+b"; i think it's a clear improvement in terms of clarity (and again, optimizations possible). --047d7b33d758e5a50404dfb2f61f Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Fri, Jun 21, 2013 at 4:14 PM, Timothee Cour <span dir=3D"ltr">&lt;<a hre= f=3D"mailto:thelastmammoth gmail.com" target=3D"_blank">thelastmammoth gmai= l.com</a>&gt;</span> wrote:<br><div class=3D"gmail_quote"><blockquote class= =3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd= ing-left:1ex"> <div class=3D"HOEnZb"><div class=3D"h5">On Fri, Jun 21, 2013 at 4:02 PM, Al= i =C7ehreli <span dir=3D"ltr">&lt;<a href=3D"mailto:acehreli yahoo.com" tar= get=3D"_blank">acehreli yahoo.com</a>&gt;</span> wrote:<br><div class=3D"gm= ail_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> <div>On 06/21/2013 03:57 PM, Diggory wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On 6/21/13 3:45 PM, Timothee Cour wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> I&#39;d like to support N-ary map, ie std.algorithm.map that takes 1 or<br> more<br> ranges as arguments and operates lazily on those.<br> </blockquote></blockquote></blockquote></blockquote> <br> </div><div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bor= der-left:1px #ccc solid;padding-left:1ex"> You can use &quot;zip&quot; from std.range.<br> </blockquote> <br></div> Timothee specifically said that he is trying to avoid zip: :)<div><div><br> <br> &gt; before:<br> &gt; =A0 zip(a,b).map!(u=3D&gt;absDiff(u[0],<u></u>u[1])).reduce!fun;<br> &gt; after:<br> &gt; =A0 map!absDiff(a,b).reduce!fun;<br> <br></div></div><span><font color=3D"#888888"> Ali<br> </font></span></blockquote></div><br></div></div><div>also works great with= string lambdas:</div><div>eg: dotproduct:</div><div><br></div><div>before:= <br>=A0 zip(u,v).map!&quot;a[0]*a[1]&quot;.reduce!&quot;a+b&quot;;<br>after= :<br> =A0 map!&quot;a*b&quot;(u,v).reduce!&quot;a+b&quot;;</div> <div><br></div><div>=3D&gt; clearer, and provides more room for optimizaton= </div><div><br></div> </blockquote></div><br><div><br></div><div>actually the version without the= proposed N-ary map is even worse, because zip uses=A0StoppingPolicy.shorte= st by default (which i find weird and contrary to D&#39;s safe by default s= tance):</div> <div><br></div><div>here&#39;s the (corrected) dotproduct:</div><div><br></= div><div>before:</div><div>=A0 zip(StoppingPolicy.requireSameLength,u,v).ma= p!&quot;a[0]*a[1]&quot;.reduce!&quot;a+b&quot;;</div><div>after:</div><div> =A0 map!&quot;a*b&quot;(u,v).reduce!&quot;a+b&quot;;</div><div><br></div><d= iv>i think it&#39;s a clear improvement in terms of clarity (and again, opt= imizations possible).</div> --047d7b33d758e5a50404dfb2f61f--
Jun 21 2013
prev sibling next sibling parent =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
On Saturday, 22 June 2013 at 00:07:40 UTC, Timothee Cour wrote:
 On Fri, Jun 21, 2013 at 4:14 PM, Timothee Cour 
 <thelastmammoth gmail.com>wrote:

 On Fri, Jun 21, 2013 at 4:02 PM, Ali Çehreli 
 <acehreli yahoo.com> wrote:

 On 06/21/2013 03:57 PM, Diggory wrote:

 On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu 
 wrote:

 On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:

 On 6/21/13 3:45 PM, Timothee Cour wrote:

 I'd like to support N-ary map, ie std.algorithm.map that 
 takes 1 or
 more
 ranges as arguments and operates lazily on those.





Timothee specifically said that he is trying to avoid zip: :)
 before:
   zip(a,b).map!(u=>absDiff(u[0],**u[1])).reduce!fun;
 after:
   map!absDiff(a,b).reduce!fun;

Ali

also works great with string lambdas: eg: dotproduct: before: zip(u,v).map!"a[0]*a[1]".reduce!"a+b"; after: map!"a*b"(u,v).reduce!"a+b"; => clearer, and provides more room for optimizaton

actually the version without the proposed N-ary map is even worse, because zip uses StoppingPolicy.shortest by default (which i find weird and contrary to D's safe by default stance): here's the (corrected) dotproduct: before: zip(StoppingPolicy.requireSameLength,u,v).map!"a[0]*a[1]".reduce!"a+b"; after: map!"a*b"(u,v).reduce!"a+b"; i think it's a clear improvement in terms of clarity (and again, optimizations possible).

Would map!"a*b"(u,v).reduce!"a+b"; be the preferred behaviour to implement a dot/scalar-product for two fixed-dimensional vectors u and v, given that they all implement the required operator overloads opRange/opSlice?
Aug 30 2013
prev sibling parent "w0rp" <devw0rp gmail.com> writes:
On Saturday, 22 June 2013 at 00:07:40 UTC, Timothee Cour wrote:
 On Fri, Jun 21, 2013 at 4:14 PM, Timothee Cour 
 <thelastmammoth gmail.com>wrote:

 On Fri, Jun 21, 2013 at 4:02 PM, Ali Çehreli 
 <acehreli yahoo.com> wrote:

 On 06/21/2013 03:57 PM, Diggory wrote:

 On Friday, 21 June 2013 at 22:56:04 UTC, Andrei Alexandrescu 
 wrote:

 On 6/21/13 3:55 PM, Andrei Alexandrescu wrote:

 On 6/21/13 3:45 PM, Timothee Cour wrote:

 I'd like to support N-ary map, ie std.algorithm.map that 
 takes 1 or
 more
 ranges as arguments and operates lazily on those.





Timothee specifically said that he is trying to avoid zip: :)
 before:
   zip(a,b).map!(u=>absDiff(u[0],**u[1])).reduce!fun;
 after:
   map!absDiff(a,b).reduce!fun;

Ali

also works great with string lambdas: eg: dotproduct: before: zip(u,v).map!"a[0]*a[1]".reduce!"a+b"; after: map!"a*b"(u,v).reduce!"a+b"; => clearer, and provides more room for optimizaton

actually the version without the proposed N-ary map is even worse, because zip uses StoppingPolicy.shortest by default (which i find weird and contrary to D's safe by default stance): here's the (corrected) dotproduct: before: zip(StoppingPolicy.requireSameLength,u,v).map!"a[0]*a[1]".reduce!"a+b"; after: map!"a*b"(u,v).reduce!"a+b"; i think it's a clear improvement in terms of clarity (and again, optimizations possible).

There we have it. zip + map is the body of the generic function desired. Optimise later if needed.
Aug 30 2013