Thread overview
feature request: N-ary map
Jun 21, 2013
Timothee Cour
Jun 21, 2013
Diggory
Jun 21, 2013
Ali Çehreli
Jun 21, 2013
Timothee Cour
Jun 22, 2013
Timothee Cour
Aug 30, 2013
Nordlöw
Aug 31, 2013
w0rp
Jun 21, 2013
Timothee Cour
June 21, 2013
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


June 21, 2013
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


June 21, 2013
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

June 21, 2013
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.
June 21, 2013
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

June 21, 2013
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;


June 21, 2013
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


June 22, 2013
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).


August 30, 2013
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?
August 31, 2013
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.