Jump to page: 1 2
Thread overview
Improving std.range.Zip
Oct 24, 2010
Tomek Sowiński
Oct 24, 2010
Philippe Sigaud
Oct 24, 2010
Tomek Sowiński
Oct 24, 2010
bearophile
Oct 24, 2010
Simen kjaeraas
Oct 24, 2010
bearophile
Oct 25, 2010
KennyTM~
Oct 25, 2010
Tomek Sowiński
Oct 25, 2010
Tomek Sowiński
Oct 25, 2010
bearophile
October 24, 2010
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
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
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
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
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
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
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
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
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
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