www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - feature request: N-ary map

reply Timothee Cour <thelastmammoth gmail.com> writes:
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
Jun 21 2013
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 reply "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
next sibling parent reply =?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
next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
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.




You can use "zip" from std.range.

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
Jun 21 2013
prev sibling parent reply Timothee Cour <thelastmammoth gmail.com> writes:
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.




You can use "zip" from std.range.

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).
Jun 21 2013
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.




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

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.




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

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
prev sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
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;
Jun 21 2013