Phobos2: zip, integral ranges, map, Any, All, Map

bearophile bearophileHUGS at lycos.com
Tue Apr 28 06:37:14 PDT 2009


Some more notes about Phobos2. Some of the things I say may be wrong because my experience with Phobos2 is limited still.

Daniel Keep:
> Not true.  Here's an excellent reason to use ranges over opApply: you
> can't define zip with opApply.  Because opApply uses inversion of
> control, you can't use more than one without bringing threads into the
> equation.

I'll try to zip two ranges that return the leaves of two different binary trees. This can be a simple example to show to attract people to D2 language :-)

So I've tried using zip:

import std.range: zip;
import std.stdio: writeln;
void main() {
    auto a = [1, 2, 3];
    string[] b = ["a", "b", "c"];
    foreach (xy; zip(a, b))
        writeln(xy.at!(0), " ", xy.at!(1));
}

That doesn't work:
...\dmd\src\phobos\std\range.d(1847): Error: template instance Zip!(int[3u],immutable(char)[][]) does not match template declaration Zip(R...) if (R.length && allSatisfy!(isInputRange,R))

probably because 'a' is a static array. Is isInputRange false for static arrays?

------------

The most basic and useful range is the one of integer numbers. How can I create with Phobos2 lazy and eager ranges like the following ones?

>>> range(1, 5)
[1, 2, 3, 4]
>>> range(5, 1, -1)
[5, 4, 3, 2]
>>> list(xrange(5, 10))
[5, 6, 7, 8, 9]
>>> list(xrange(5, 10, 2))
[5, 7, 9]

Similar ranges are useful with map,zip, and in many other situations.
(I hope the x..y range syntax of D2 foreach will evolve in a syntax that can be used everywhere an integral range can be used).

------------

The docs say about "map":

>Multiple functions can be passed to map. In that case, the element type of map is a tuple containing one element for each function.<
> [...]
> foreach (e; map!("a + a", "a * a")(arr1))

Having the possibility to map two functions in parallel may be useful in some situations (where for example computing the items is costly) but quite more useful can be to map a function that takes two or more arguments. An example:

>>> map(lambda x, y: x*y, ["a", "b", "c"], xrange(1, 4))
['a', 'bb', 'ccc']

If you don't have that you are forced to use a zip inside the map, but then you also are forced to change the D2 mapping function to something like:
(p){ return p.at!(0) * p.at!(1); }

----------

all() and any() functions are useful to test if all or any items of an iterable are true (with optinal mapping function too). They are useful as templates too, so I suggest to rename allSatisfy as "All" and "anySatisfy" as "Any".
A similar template named "Map" can be created if not already present, to map a given template to a typetuple.

In future I'll probably write more notes, suggestions and questions about Phobos2. I hope such notes are very useful.

Bye,
bearophile



More information about the Digitalmars-d mailing list