www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how to return map(fn)

reply steve <stevethe1st gmail.com> writes:
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?
Feb 21 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Feb 21 2022
parent reply steve <stevethe1st gmail.com> writes:
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.]); ```
Feb 22 2022
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
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 ```d 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: ```d 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
Feb 22 2022
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Feb 22 2022
parent reply steve <stevethe1st gmail.com> writes:
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.]));
}```
Feb 23 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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!


 ```d
 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 ;) ```d 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
Feb 23 2022
parent steve <stevethe1st gmail.com> writes:
 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!
Feb 24 2022