Thread overview
How to instantiate a map with multiple functions
Dec 26, 2015
karthikeyan
Dec 26, 2015
Fusxfaranto
Dec 26, 2015
karthikeyan
Dec 27, 2015
Ali Çehreli
Dec 27, 2015
Karthikeyan
Dec 27, 2015
Ali Çehreli
Dec 27, 2015
Jay Norwood
Dec 27, 2015
Jay Norwood
Dec 27, 2015
karthikeyan
December 26, 2015
How to instantiate a map with multiple functions. I looked into the docs at http://dlang.org/phobos/std_algorithm_iteration.html#map. They contain a string which I suppose is a mixin and when I change "a" to some other name it results in an error for me. Are there any ways to use lambda functions directly instead of strings and any explanation of the strings used in the map example and why a is used will be helpful.

I tried reading the source https://github.com/D-Programming-Language/phobos/blob/master/std/algorithm/iteration.d#L520 .Some hint that "a" should be used at https://github.com/D-Programming-Language/phobos/blob/master/std/functional.d#L101 but how do I change that since map doesn't allow me any params to specify the parameter name. Also how can I map an array of tuples with two or more elements with a function of two or more params like unpack the tuple into a function like that. I am D beginner so any will insights will be very helpful for me.

I am using dmd version 2.069 on Linux Mint 15 - 64bit
December 26, 2015
On Saturday, 26 December 2015 at 19:30:24 UTC, karthikeyan wrote:
> How to instantiate a map with multiple functions. I looked into the docs at http://dlang.org/phobos/std_algorithm_iteration.html#map. They contain a string which I suppose is a mixin and when I change "a" to some other name it results in an error for me. Are there any ways to use lambda functions directly instead of strings and any explanation of the strings used in the map example and why a is used will be helpful.
>
> I tried reading the source https://github.com/D-Programming-Language/phobos/blob/master/std/algorithm/iteration.d#L520 .Some hint that "a" should be used at https://github.com/D-Programming-Language/phobos/blob/master/std/functional.d#L101 but how do I change that since map doesn't allow me any params to specify the parameter name. Also how can I map an array of tuples with two or more elements with a function of two or more params like unpack the tuple into a function like that. I am D beginner so any will insights will be very helpful for me.
>
> I am using dmd version 2.069 on Linux Mint 15 - 64bit

You should be able to just use any function (including lambdas) as a template argument to map.  The string version is from before the more concise "=>" lambda syntax was developed, and generally isn't what you want to use nowadays.
December 26, 2015
On Saturday, 26 December 2015 at 19:38:16 UTC, Fusxfaranto wrote:
> On Saturday, 26 December 2015 at 19:30:24 UTC, karthikeyan wrote:
>> How to instantiate a map with multiple functions. I looked into the docs at http://dlang.org/phobos/std_algorithm_iteration.html#map. They contain a string which I suppose is a mixin and when I change "a" to some other name it results in an error for me. Are there any ways to use lambda functions directly instead of strings and any explanation of the strings used in the map example and why a is used will be helpful.
>>
>> I tried reading the source https://github.com/D-Programming-Language/phobos/blob/master/std/algorithm/iteration.d#L520 .Some hint that "a" should be used at https://github.com/D-Programming-Language/phobos/blob/master/std/functional.d#L101 but how do I change that since map doesn't allow me any params to specify the parameter name. Also how can I map an array of tuples with two or more elements with a function of two or more params like unpack the tuple into a function like that. I am D beginner so any will insights will be very helpful for me.
>>
>> I am using dmd version 2.069 on Linux Mint 15 - 64bit
>
> You should be able to just use any function (including lambdas) as a template argument to map.  The string version is from before the more concise "=>" lambda syntax was developed, and generally isn't what you want to use nowadays.

Thanks but the following returns an error for me

  import std.algorithm.comparison : equal;
  import std.range : chain;
  int[] arr1 = [ 1, 2, 3, 4 ];
  int[] arr2 = [ 5, 6 ];
  auto dd = map!(z => z * z, c => c * c * c)(chain(arr1, arr2));
  writeln(dd);

Error :

/usr/include/dmd/phobos/std/meta.d(546): Error: template instance F!(__lambda2) cannot use local '__lambda2' as parameter to non-global template AppliedReturnType(alias f)
/usr/include/dmd/phobos/std/meta.d(552): Error: template instance maps_square.main.staticMap!(AppliedReturnType, __lambda2) error instantiating
/usr/include/dmd/phobos/std/algorithm/iteration.d(447):        instantiated from here: staticMap!(AppliedReturnType, __lambda2, __lambda3)
maps_square.d(71):        instantiated from here: map!(Result)
/usr/include/dmd/phobos/std/meta.d(546): Error: template instance F!(__lambda3) cannot use local '__lambda3' as parameter to non-global template AppliedReturnType(alias f)
/usr/include/dmd/phobos/std/meta.d(553): Error: template instance maps_square.main.staticMap!(AppliedReturnType, __lambda3) error instantiating
/usr/include/dmd/phobos/std/algorithm/iteration.d(447):        instantiated from here: staticMap!(AppliedReturnType, __lambda2, __lambda3)
maps_square.d(71):        instantiated from here: map!(Result)

Am I missing something here over how the lambda notation can be used? I personally prefer the lambda notation to be clear than passing strings as arguments. Kindly help me on this.
December 26, 2015
On 12/26/2015 11:46 AM, karthikeyan wrote:

> Thanks but the following returns an error for me
>
>    import std.algorithm.comparison : equal;
>    import std.range : chain;
>    int[] arr1 = [ 1, 2, 3, 4 ];
>    int[] arr2 = [ 5, 6 ];
>    auto dd = map!(z => z * z, c => c * c * c)(chain(arr1, arr2));
>    writeln(dd);
>
> Error :
>
> /usr/include/dmd/phobos/std/meta.d(546): Error: template instance
> F!(__lambda2) cannot use local '__lambda2' as parameter to non-global
> template AppliedReturnType(alias f)

That looks like a bug to me. Please report here:

  https://issues.dlang.org/

You can call tuple() as a workaround:

import std.stdio;
import std.algorithm;
import std.range;
import std.typecons;

void main() {
    int[] arr1 = [ 1, 2, 3, 4 ];
    int[] arr2 = [ 5, 6 ];
    auto dd = map!(z => tuple(z * z, z * z * z))(chain(arr1, arr2));
    writeln(dd);
}

Ali

December 27, 2015
On Sunday, 27 December 2015 at 00:27:12 UTC, Ali Çehreli wrote:
> On 12/26/2015 11:46 AM, karthikeyan wrote:
>
> > Thanks but the following returns an error for me
> >
> >    import std.algorithm.comparison : equal;
> >    import std.range : chain;
> >    int[] arr1 = [ 1, 2, 3, 4 ];
> >    int[] arr2 = [ 5, 6 ];
> >    auto dd = map!(z => z * z, c => c * c * c)(chain(arr1,
> arr2));
> >    writeln(dd);
> >
> > Error :
> >
> > /usr/include/dmd/phobos/std/meta.d(546): Error: template
> instance
> > F!(__lambda2) cannot use local '__lambda2' as parameter to
> non-global
> > template AppliedReturnType(alias f)
>
> That looks like a bug to me. Please report here:
>
>   https://issues.dlang.org/
>
> You can call tuple() as a workaround:
>
> import std.stdio;
> import std.algorithm;
> import std.range;
> import std.typecons;
>
> void main() {
>     int[] arr1 = [ 1, 2, 3, 4 ];
>     int[] arr2 = [ 5, 6 ];
>     auto dd = map!(z => tuple(z * z, z * z * z))(chain(arr1, arr2));
>     writeln(dd);
> }
>
> Ali

Thanks Ali. I think it's been around like this for a long time. I searched issue tracker but no issues of this type. Also if I need to map on a array of tuples will that work with the tuple being unpacked or do I need to get it as single element and do unpacking myself? Sorry on mobile so couldn't check.
December 26, 2015
On 12/26/2015 05:26 PM, Karthikeyan wrote:

> if I need to map on a array of tuples will that work with the tuple being
> unpacked or do I need to get it as single element and do unpacking myself?

Unfortunately, there is no automatic unpacking of tuples.

The only exception that I know is when tuples are elements of a range (but not a proper slice, in which case the first element is the automatic element index).

import std.stdio;
import std.typecons;
import std.range;
import std.algorithm;

void main() {
    auto range = 5.iota.map!(i => tuple(2 * i, i * i));

    // automatic tuple expansion:
    foreach (twice, square; range) {
        writefln("twice: %s, square: %s", twice, square);
    }
}

Prints:

twice: 0, square: 0
twice: 2, square: 1
twice: 4, square: 4
twice: 6, square: 9
twice: 8, square: 16

The problem is when the same elements are inside a slice:

import std.stdio;
import std.typecons;
import std.range;
import std.algorithm;

void main() {
    auto range = [ tuple(0, 0), tuple(2, 1) ];

    foreach (twice, square; range) {
        writefln("twice: %s, square: %s", twice, square);
    }
}

Now 'twice' is the automatic index, and 'square' is the entire element (i.e. the tuple):

twice: 0, square: Tuple!(int, int)(0, 0)
twice: 1, square: Tuple!(int, int)(2, 1)

Ali

December 27, 2015
I'm playing around with something also trying to apply multiple functions.
In my case, a sample is some related group of measurements taken simultaneously, and I'm calculating a group of metrics from the measured data of each sample.

This produces the correct results for the input data, and it seems pretty clear what functions are being applied.

I would probably want to associate names with the tuple metric results, and I've seen that somewhere in the docs in parameter tuples.   I suppose I'll try those in place of the current tuple ...

import std.stdio;
import std.algorithm;
import std.conv;
import std.range;
import std.typecons;

struct S { ulong a; ulong b; ulong c; ulong d; double e; ulong f;}

ulong f1(ref S s) { with(s){return a+b;}}
double f2(ref S s) { with(s){return (c+d)/e;}}
double f3(ref S s) { with(s){return (c+f)/e;}}

int main()
{

	S[10] samples;
	// initialize some values
	foreach ( int i, ref s; samples){
		int j=i+1;
		with (s){
			a=j; b=j*2; c=j*3; d=j*4; e=j*10; f=j*5;
		}
	}

	// apply several functions on each  sample
	samples.each!((int i, ref a)=>tuple(i,f1(a),f2(a),f3(a)).writeln());
	return 0;
}

========== output is

Tuple!(int, ulong, double, double)(0, 3, 0.7, 0.8)
Tuple!(int, ulong, double, double)(1, 6, 0.7, 0.8)
Tuple!(int, ulong, double, double)(2, 9, 0.7, 0.8)
Tuple!(int, ulong, double, double)(3, 12, 0.7, 0.8)
Tuple!(int, ulong, double, double)(4, 15, 0.7, 0.8)
Tuple!(int, ulong, double, double)(5, 18, 0.7, 0.8)
Tuple!(int, ulong, double, double)(6, 21, 0.7, 0.8)
Tuple!(int, ulong, double, double)(7, 24, 0.7, 0.8)
Tuple!(int, ulong, double, double)(8, 27, 0.7, 0.8)
Tuple!(int, ulong, double, double)(9, 30, 0.7, 0.8)


December 27, 2015
On Sunday, 27 December 2015 at 03:22:50 UTC, Jay Norwood wrote:
> I would probably want to associate names with the tuple metric results, and I've seen that somewhere in the docs in parameter tuples.   I suppose I'll try those in place of the current tuple ...
>

This worked to associate names with the tuple values. Just the one line modified.
samples.each!((int i, ref a)=>tuple!("sample","f1","f2","f3")(i,f1(a),f2(a),f3(a)).writeln());

======= output
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(0, 3, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(1, 6, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(2, 9, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(3, 12, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(4, 15, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(5, 18, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(6, 21, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(7, 24, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(8, 27, 0.7, 0.8)
Tuple!(int, "sample", ulong, "f1", double, "f2", double, "f3")(9, 30, 0.7, 0.8)

December 27, 2015
On Sunday, 27 December 2015 at 02:21:11 UTC, Ali Çehreli wrote:
> On 12/26/2015 05:26 PM, Karthikeyan wrote:
>
> > if I need to map on a array of tuples will that work with the
> tuple being
> > unpacked or do I need to get it as single element and do
> unpacking myself?
>
> Unfortunately, there is no automatic unpacking of tuples.
>
> The only exception that I know is when tuples are elements of a range (but not a proper slice, in which case the first element is the automatic element index).
>
> import std.stdio;
> import std.typecons;
> import std.range;
> import std.algorithm;
>
> void main() {
>     auto range = 5.iota.map!(i => tuple(2 * i, i * i));
>
>     // automatic tuple expansion:
>     foreach (twice, square; range) {
>         writefln("twice: %s, square: %s", twice, square);
>     }
> }
>
> Prints:
>
> twice: 0, square: 0
> twice: 2, square: 1
> twice: 4, square: 4
> twice: 6, square: 9
> twice: 8, square: 16
>
> The problem is when the same elements are inside a slice:
>
> import std.stdio;
> import std.typecons;
> import std.range;
> import std.algorithm;
>
> void main() {
>     auto range = [ tuple(0, 0), tuple(2, 1) ];
>
>     foreach (twice, square; range) {
>         writefln("twice: %s, square: %s", twice, square);
>     }
> }
>
> Now 'twice' is the automatic index, and 'square' is the entire element (i.e. the tuple):
>
> twice: 0, square: Tuple!(int, int)(0, 0)
> twice: 1, square: Tuple!(int, int)(2, 1)
>
> Ali

I took a local copy of the std.algorithm.iteration as myiteration.d and used it for debugging. Commenting out the following two lines make this work https://github.com/D-Programming-Language/phobos/blob/master/std/algorithm/iteration.d#L461-L463. I don't know why that fails. I filed an issue at the bug tracker.