higher-order funcs for ranges (with usual interface)

Lars T. Kyllingstad public at kyllingen.NOSPAMnet
Wed Feb 2 05:18:07 PST 2011


On Wed, 02 Feb 2011 13:26:39 +0100, spir wrote:

> Hello,
> 
> This bit of code for arrays:
> 
> Out[] map (In,Out) (In[] input, Out delegate (In) f) {
>      Out[] output = new Out[](input.length); foreach (i,item ; input)
>          output [i] = f(item);
>      return output;
> }
> unittest {
>      char character (uint code) {return cast(char)code;} uint[] codes =
>      [0x61,0x62,0x63];
>      // functional style
>      writeln(map(codes, &character));    // "abc" // OO style
>      writeln(codes.map(&character));     // "abc"
> }
> 
> How to write this for ranges? [...]
>
> For ranges, I'm looking for something similar to:
>      Range!Out map (In,Out) (Range!In input, Out delegate (In) f) {...}
> Indeed, the compiler should understand that Range!T is a type id just
> like T[].

I don't think it's possible to do it exactly as you describe.  I mean, 
Range in that case can be anything, and you can't always return a range 
of the same kind.  Two possibilities are, you can do it eagerly,

  Out[] map(Range, In, Out)(Range input, Out delegate(In) f)
      if (isInputRange!Range && is(ElementType!Range : In))
  {
      ...
  }

or you can do it lazily by defining your own map range (untested):

  struct Map(Range, In, Out)
      if (isInputRange!Range && is(ElementType!Range : In)
  {
      Range input;
      Out delegate(In) f;

      @property bool empty() { return input.empty; }

      // Inefficient, should cache front...
      @property Out front() { return f(input.front); }
      
      void popFront() { input.popFront(); }
  }

  Map!(Range, Out) map(Range, In, Out)(Range input, Out delegate(In) f)
      if (isInputRange!R && is(ElementType!Range : In)
  {
      return typeof(return)(input, f);
  }

-Lars


More information about the Digitalmars-d-learn mailing list