View mode: basic / threaded / horizontal-split · Log in · Help
October 24, 2010
Improving std.range.Zip
I have noticed an emerging idiom in my code lately: bring together n  
ranges, transform them to one range using a n-ary function. Currently it's  
achieved with:

map!((a) {return myNaryFun(a._0, a._1, ...); })(zip(range1, range2, ...));

It's a bit of a nuisanse -- rarely do my transforming functions take  
tuples, and there's the necessity of composing 2 higher-order ranges to  
render fairly common functionality. I think Zip could be further  
parametrized with a zipper function, so that the above code would boil  
down to:

zip!myNaryFun(range1, range2, ...);

Having looked at Zip's source, such change shouldn't be a big deal. Oh,  
and the default zipper function would be std.typecons.tuple, not to  
trouble those not keen on generalization.

Good?

-- 
Tomek
October 24, 2010
Re: Improving std.range.Zip
2010/10/24 Tomek Sowiński <just@ask.me>:
> I have noticed an emerging idiom in my code lately: bring together n ranges,
> transform them to one range using a n-ary function. Currently it's achieved
> with:
>
> map!((a) {return myNaryFun(a._0, a._1, ...); })(zip(range1, range2, ...));
>
> It's a bit of a nuisanse -- rarely do my transforming functions take tuples,
> and there's the necessity of composing 2 higher-order ranges to render
> fairly common functionality. I think Zip could be further parametrized with
> a zipper function, so that the above code would boil down to:
>
> zip!myNaryFun(range1, range2, ...);
>
> Having looked at Zip's source, such change shouldn't be a big deal. Oh, and
> the default zipper function would be std.typecons.tuple, not to trouble
> those not keen on generalization.

That's what Haskell calls ZipWith. I called it tmap (as in tuple-map)
when I needed it in D.
IMHO, it should be a generalization of std.algorithm.map: let it
accept n ranges and a n-ary function. It can even do a partial check
at compile-time.
Extending filter() and reduce() to work with n ranges in parallel and
a n-args function is also useful.

you may be interested in looking there:

http://www.dsource.org/projects/dranges/

(more specifically, in the algorithm module)

Philippe
October 24, 2010
Re: Improving std.range.Zip
Tomek S.:

> map!((a) {return myNaryFun(a._0, a._1, ...); })(zip(range1, range2, ...));

Currently the docs of std.algorithm.map say:

>Multiple functions can be passed to map. In that case, the element type of map  is a tuple containing one element for each function.<

But lot of time ago I have said that in my opinion that's not the best design. Python has a different design, its map does what you want, you may write your code in Python as:

map(myNaryFun, range1, range2, ...)

An example (Python 2.6):

>>> a = ["a", "b", "c", "d"]
>>> b = [1, 2, 3, 4]
>>> map(lambda c,n: c * n, a, b)
['a', 'bb', 'ccc', 'dddd']

Is is possible to change the std.algorithm.map to a semantics similar to the Python one, that I think is more useful?

Bye,
bearophile
October 24, 2010
Re: Improving std.range.Zip
On Sun, 24 Oct 2010 21:39:24 +0200, bearophile <bearophileHUGS@lycos.com>  
wrote:

> Tomek S.:
>
>> map!((a) {return myNaryFun(a._0, a._1, ...); })(zip(range1, range2,  
>> ...));
>
> Currently the docs of std.algorithm.map say:
>
>> Multiple functions can be passed to map. In that case, the element type  
>> of map  is a tuple containing one element for each function.<
>
> But lot of time ago I have said that in my opinion that's not the best  
> design. Python has a different design, its map does what you want, you  
> may write your code in Python as:
>
> map(myNaryFun, range1, range2, ...)
>
> An example (Python 2.6):
>
>>>> a = ["a", "b", "c", "d"]
>>>> b = [1, 2, 3, 4]
>>>> map(lambda c,n: c * n, a, b)
> ['a', 'bb', 'ccc', 'dddd']
>
> Is is possible to change the std.algorithm.map to a semantics similar to  
> the Python one, that I think is more useful?

From what I can see, map currently simply doesn't support passing it
multiple ranges. It would be a trivial change to let it support multiple
ranges in addition to multiple functions.


-- 
Simen
October 24, 2010
Re: Improving std.range.Zip
Dnia 24-10-2010 o 21:34:54 Philippe Sigaud <philippe.sigaud@gmail.com>  
napisał(a):

> That's what Haskell calls ZipWith. I called it tmap (as in tuple-map)
> when I needed it in D.
> IMHO, it should be a generalization of std.algorithm.map: let it
> accept n ranges and a n-ary function. It can even do a partial check
> at compile-time.

It could be. As long as the job gets done it doesn't matter what will be  
generalized, Map or Zip. One will cover other's functionality entirely.

> Extending filter() and reduce() to work with n ranges in parallel and
> a n-args function is also useful.
> you may be interested in looking there:
> http://www.dsource.org/projects/dranges/
> (more specifically, in the algorithm module)

Nice lib. Any plans to incorporate some of it to Phobos?

-- 
Tomek
October 24, 2010
Re: Improving std.range.Zip
Simen kjaeraas:

>  From what I can see, map currently simply doesn't support passing it
> multiple ranges. It would be a trivial change to let it support multiple
> ranges in addition to multiple functions.

If you may have multiple of both then the situation becomes complex. So I think that single function - multiple ranges is simpler & better than that :-)

Bye,
bearophile
October 25, 2010
Re: Improving std.range.Zip
On 10/24/10 14:55 CDT, Simen kjaeraas wrote:
> On Sun, 24 Oct 2010 21:39:24 +0200, bearophile
> <bearophileHUGS@lycos.com> wrote:
>
>> Tomek S.:
>>
>>> map!((a) {return myNaryFun(a._0, a._1, ...); })(zip(range1, range2,
>>> ...));
>>
>> Currently the docs of std.algorithm.map say:
>>
>>> Multiple functions can be passed to map. In that case, the element
>>> type of map is a tuple containing one element for each function.<
>>
>> But lot of time ago I have said that in my opinion that's not the best
>> design. Python has a different design, its map does what you want, you
>> may write your code in Python as:
>>
>> map(myNaryFun, range1, range2, ...)
>>
>> An example (Python 2.6):
>>
>>>>> a = ["a", "b", "c", "d"]
>>>>> b = [1, 2, 3, 4]
>>>>> map(lambda c,n: c * n, a, b)
>> ['a', 'bb', 'ccc', 'dddd']
>>
>> Is is possible to change the std.algorithm.map to a semantics similar
>> to the Python one, that I think is more useful?
>
>  From what I can see, map currently simply doesn't support passing it
> multiple ranges. It would be a trivial change to let it support multiple
> ranges in addition to multiple functions.

This is coming full circle. At a point, map _did_ support multiple 
ranges. Some people found that non-modular - if you want multiple 
ranges, you should use map with zip...

Andrei
October 25, 2010
Re: Improving std.range.Zip
On Oct 25, 10 14:04, Andrei Alexandrescu wrote:
> This is coming full circle. At a point, map _did_ support multiple
> ranges. Some people found that non-modular - if you want multiple
> ranges, you should use map with zip...

Except that at "that point"[1], map's multi-range support is equivalent to

    map!(func)(r1, r2, r3...) ==  map!(func)(chain(r1, r2, r3...))

which is hardly useful. OTOH zipWithN is a very useful higher-order 
function.

[1]: 
http://web.archive.org/web/20080417051734/www.digitalmars.com/d/2.0/phobos/std_algorithm.html#map
October 25, 2010
Re: Improving std.range.Zip
On 10/25/10 1:42 CDT, KennyTM~ wrote:
> On Oct 25, 10 14:04, Andrei Alexandrescu wrote:
>> This is coming full circle. At a point, map _did_ support multiple
>> ranges. Some people found that non-modular - if you want multiple
>> ranges, you should use map with zip...
>
> Except that at "that point"[1], map's multi-range support is equivalent to
>
> map!(func)(r1, r2, r3...) == map!(func)(chain(r1, r2, r3...))
>
> which is hardly useful. OTOH zipWithN is a very useful higher-order
> function.
>
> [1]:
> http://web.archive.org/web/20080417051734/www.digitalmars.com/d/2.0/phobos/std_algorithm.html#map

Oh, you're right. Sorry!

Andrei
October 25, 2010
Re: Improving std.range.Zip
Dnia 25-10-2010 o 08:42:31 KennyTM~ <kennytm@gmail.com> napisał(a):

> On Oct 25, 10 14:04, Andrei Alexandrescu wrote:
>> This is coming full circle. At a point, map _did_ support multiple
>> ranges. Some people found that non-modular - if you want multiple
>> ranges, you should use map with zip...
>
> Except that at "that point"[1], map's multi-range support is equivalent  
> to
>
>      map!(func)(r1, r2, r3...) ==  map!(func)(chain(r1, r2, r3...))
>
> which is hardly useful. OTOH zipWithN is a very useful higher-order  
> function.
>
> [1]:  
> http://web.archive.org/web/20080417051734/www.digitalmars.com/d/2.0/phobos/std_algorithm.html#map

You're right. Still, modularity is a valid point. Thinking about it, this  
can be a good exercise in static inheritance -- make Zip the base taking  
care of multi-range traversal (stopping policy, etc) and the "derived"  
ranges (Map, Filter, Reduce) would only implement element accessors,  
transformation, and so on.

-- 
Tomek
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home