Thread overview
how to return map(fn)
Feb 21, 2022
steve
Feb 21, 2022
Ali Çehreli
Feb 22, 2022
steve
Feb 22, 2022
Ali Çehreli
Feb 23, 2022
steve
Feb 24, 2022
steve
February 21, 2022

following this example in the documentation of map:

import std.algorithm.comparison : equal;
import std.conv : to;

alias stringize = map!(to!string);
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));

I would like to write a function that takes as its parameter a function and returns something like the alias in the example. i.e. something like:

float[] function(float[]) get_map(alias f){
   return map!(f)
}

I had a look at the source code for map but it seems to return a private struct, which doesn't help. Is there any way to get this to work?

February 21, 2022
On 2/21/22 12:44, steve wrote:

> I had a look at the source code for map but it seems to return a private
> struct, which doesn't help.

What map and other Phobos algorithms return are called Voldemort types for the reason you state: They are unmentionable. The usual way is to return 'auto' and the template system will take care of the rest:

auto mapped(alias f, Range) (Range range) {
  import std.algorithm : map;
  return range.map!f();
}

void main() {
  auto r = [1, 2].mapped!(i => 10 * i);

  import std.algorithm;
  assert(r.equal([10, 20]));
}

And I am sure your function is more capable than being the equivalent as map. ;)

Ali

February 22, 2022

On Monday, 21 February 2022 at 23:07:44 UTC, Ali Çehreli wrote:

>

On 2/21/22 12:44, steve wrote:
...

thanks for your help. I'm unfortunately still a bit confused. Maybe I wasn't clear or maybe I'm just missing something here. What I was trying to return is function that can then be applied to e.g. an array. As I understand the mapped function you wrote expects a range and a function argument something that would let me do

float my_function(float x){ return 2*x;}

auto my_function_mapped = mapped(my_function);
assert(my_function_mapped([1.,2.,3.]) == [2.,4.,6.]);

February 22, 2022

On Tuesday, 22 February 2022 at 13:53:34 UTC, steve wrote:

>

On Monday, 21 February 2022 at 23:07:44 UTC, Ali Çehreli wrote:

>

On 2/21/22 12:44, steve wrote:
...

thanks for your help. I'm unfortunately still a bit confused. Maybe I wasn't clear or maybe I'm just missing something here. What I was trying to return is function that can then be applied to e.g. an array. As I understand the mapped function you wrote expects a range and a function argument something that would let me do

float my_function(float x){ return 2*x;}

auto my_function_mapped = mapped(my_function);
assert(my_function_mapped([1.,2.,3.]) == [2.,4.,6.]);

map does not eagerly allocate or process data. map is actually a lazy function, meaning it doesn't actually run until you look at the elements.

If you want a concrete range, you can use array from std.array as follows:

float[] get_map(alias f)(float[] input){
   import std.algorithm : map;
   import std.array : array;
   return input.map!(f).array;
}

array iterates all elements in the range and allocates a new array to hold the data.

I know in other languages, people are used to just using arrays for all high-level composition, but D tries not to incur the allocation/copy penalty if it can help it. So it's worth questioning if you actually need an array, or if you can just use the map result directly.

-Steve

February 22, 2022
On 2/22/22 05:53, steve wrote:

> What I was trying
> to return is function that can then be applied to e.g. an array.

I think an eponymous template that defines an alias as in your original post can be used as well:

template mappified(alias func) {
  import std.algorithm : map;
  alias mappified = map!func;
}

void main() {
  import std.stdio;
  writeln([1,2].mappified!(a => a * 10));
}

There is std.functional which includes function composition tools:

  https://dlang.org/phobos/std_functional.html

Ali

February 23, 2022

Thank you both a lot for your help. I am new to D so all of this is incredibly helpful. This seems like an amazing community!

@Ali I will have a look at std.functional as I think this is really what I was looking for. Until then, I have solved the problem with a simple class (e.g. below). I'm sure its not a particularly good way of doing it but it will work for now :). Also thank you for your book, its amazing!

class Mapper
{
    float function(float) fn;

    this(float function(float) func)  {this.fn = func;}

    float[] opCall(float[] x){
        auto arr = new float[x.length];
        foreach (i,elem; x) { arr[i] = fn(elem);}
        return arr;
    }

}


float times_two(float x) {return 2*x;}


void main() {

    import std.stdio;

    Mapper map2x = new Mapper(&times_two);
    writeln(map2x([1., 2., 3.]));
}```
February 23, 2022

On Wednesday, 23 February 2022 at 16:48:00 UTC, steve wrote:

>

Thank you both a lot for your help. I am new to D so all of this is incredibly helpful. This seems like an amazing community!

@Ali I will have a look at std.functional as I think this is really what I was looking for. Until then, I have solved the problem with a simple class (e.g. below). I'm sure its not a particularly good way of doing it but it will work for now :). Also thank you for your book, its amazing!

class Mapper
{
    float function(float) fn;

    this(float function(float) func)  {this.fn = func;}

    float[] opCall(float[] x){
        auto arr = new float[x.length];
        foreach (i,elem; x) { arr[i] = fn(elem);}
        return arr;
    }

}


float times_two(float x) {return 2*x;}


void main() {

    import std.stdio;

    Mapper map2x = new Mapper(&times_two);
    writeln(map2x([1., 2., 3.]));
}

I'm not sure what programming languages you are used to, so let me just show you the idiomatic D way ;)

float times_two(float x) {return 2*x;}

// if you would rather make sure the result is an array
float[] times_two_array(float[] arr) {
   import std.algorithm; // for map
   import std.array; // for array
   return arr
      .map!times_two // map your function
      .array; // convert to an array
}

void main() {
   import std.stdio;
   import std.algorithm; // for map
   alias map2x = map!times_two;
   writeln(map2x([1., 2., 3.]));
   float[] arr2 = times_two_array([1., 2., 3.]);
   writeln(arr2);
}

-Steve

February 24, 2022
>

float times_two(float x) {return 2*x;}

// if you would rather make sure the result is an array
float[] times_two_array(float[] arr) {
import std.algorithm; // for map
import std.array; // for array
return arr
.map!times_two // map your function
.array; // convert to an array
}

void main() {
import std.stdio;
import std.algorithm; // for map
alias map2x = map!times_two;
writeln(map2x([1., 2., 3.]));
float[] arr2 = times_two_array([1., 2., 3.]);
writeln(arr2);
}


-Steve

that is exactly what I was trying to achieve thank you so much!