www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to instantiate a map with multiple functions

reply karthikeyan <tir.karthi gmail.com> writes:
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/algori
hm/iteration.d#L520 .Some hint that "a" should be used at
https://github.com/D-Programming-Language/phobos/blob/master/s
d/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
Dec 26 2015
parent reply Fusxfaranto <fusxfaranto gmail.com> writes:
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/algori
hm/iteration.d#L520 .Some hint that "a" should be used at
https://github.com/D-Programming-Language/phobos/blob/master/s
d/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.
Dec 26 2015
parent reply karthikeyan <tir.karthi gmail.com> writes:
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/algori
hm/iteration.d#L520 .Some hint that "a" should be used at
https://github.com/D-Programming-Language/phobos/blob/master/s
d/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.
Dec 26 2015
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Dec 26 2015
parent reply Karthikeyan <tir.karthi gmail.com> writes:
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.
Dec 26 2015
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Dec 26 2015
next sibling parent reply Jay Norwood <jayn prismnet.com> writes:
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)
Dec 26 2015
parent Jay Norwood <jayn prismnet.com> writes:
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)
Dec 26 2015
prev sibling parent karthikeyan <tir.karthi gmail.com> writes:
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/it ration.d#L461-L463. I don't know why that fails. I filed an issue at the bug tracker.
Dec 27 2015