www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - std.algorithm each documentation terse

reply "jmh530" <john.michael.hall gmail.com> writes:
I have found the documentation for each in std.algorithm a bit 
terse. It seemed like it was an eager version of map, but it 
seems to be a bit more limited than that.

In particular, the documentation says that if you can mutate the 
value in place, then you can call each on it. The first thing I 
noticed is that this works easiest (beyond in place operators) 
when you're using a void function and taking the input you want 
to change as ref. This is what I did in the foo and bar functions 
below. However, it's not the same thing as just applying the 
function. In the baz function, I mutate the value and then return 
a different value. Using baz with each doesn't change the value 
by 2, only by 1.

What really confused me is that I can't use a lambda with each in 
a similar way as map. I think this is because the lambdas I'm 
using really aren't void functions. The part after the => is 
basically a return statement, so I'm not really mutating anything 
in place. Is there any way to do this with lambdas or are void 
functions required?

Is there a way to write a void lambda that would work with each?

import std.range : iota;
import std.algorithm : each;
import std.array : array;

void foo(ref int x)
{
	x += 1;
}

void bar(ref int x)
{
	x *= x;
}

int baz(ref int x)
{
	x += 1;
	return x + 1;
}

void main()
{
	auto x = iota(3).array;
	
	x.each!((ref a) => a++);
	assert(x == [1, 2, 3]); //What you would expect
	
	x.each!((ref a) => foo(a));
	assert(x == [2, 3, 4]); //What you would expect
	
	x.each!((ref a) => bar(a));
	assert(x == [4, 9, 16]); //What you would expect
	
	x.each!((ref a) => baz(a));
	assert(x == [5, 10, 17]); //What I would expect after thinking 
about it for a while
							
	x.each!((ref a) => a + 1);
	assert(x == [5, 10, 17]); //Not what I would expect
	
	x.each!((ref a) => a * a);
	assert(x == [5, 10, 17]); //Not what I would expect
}
Jul 20 2015
next sibling parent "jmh530" <john.michael.hall gmail.com> writes:
On Monday, 20 July 2015 at 14:40:59 UTC, jmh530 wrote:
 Is there a way to write a void lambda that would work with each?
Ugh, I hate that I can't edit posts. I meant to delete this line.
Jul 20 2015
prev sibling next sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 20 July 2015 at 14:40:59 UTC, jmh530 wrote:
 I have found the documentation for each in std.algorithm a bit 
 terse. It seemed like it was an eager version of map, but it 
 seems to be a bit more limited than that.

 In particular, the documentation says that if you can mutate 
 the value in place, then you can call each on it. The first 
 thing I noticed is that this works easiest (beyond in place 
 operators) when you're using a void function and taking the 
 input you want to change as ref. This is what I did in the foo 
 and bar functions below. However, it's not the same thing as 
 just applying the function. In the baz function, I mutate the 
 value and then return a different value. Using baz with each 
 doesn't change the value by 2, only by 1.

 What really confused me is that I can't use a lambda with each 
 in a similar way as map. I think this is because the lambdas 
 I'm using really aren't void functions. The part after the => 
 is basically a return statement, so I'm not really mutating 
 anything in place. Is there any way to do this with lambdas or 
 are void functions required?

 Is there a way to write a void lambda that would work with each?

 import std.range : iota;
 import std.algorithm : each;
 import std.array : array;

 void foo(ref int x)
 {
 	x += 1;
 }

 void bar(ref int x)
 {
 	x *= x;
 }

 int baz(ref int x)
 {
 	x += 1;
 	return x + 1;
 }

 void main()
 {
 	auto x = iota(3).array;
 	
 	x.each!((ref a) => a++);
 	assert(x == [1, 2, 3]); //What you would expect
 	
 	x.each!((ref a) => foo(a));
 	assert(x == [2, 3, 4]); //What you would expect
 	
 	x.each!((ref a) => bar(a));
 	assert(x == [4, 9, 16]); //What you would expect
 	
 	x.each!((ref a) => baz(a));
 	assert(x == [5, 10, 17]); //What I would expect after thinking 
 about it for a while
 							
 	x.each!((ref a) => a + 1);
 	assert(x == [5, 10, 17]); //Not what I would expect
 	
 	x.each!((ref a) => a * a);
 	assert(x == [5, 10, 17]); //Not what I would expect
 }
Everything is exactly as I would expect. Lambdas with => are just shorthand that skips the return expression and std.algorithm.each just calls the lambda for each element in x, it doesn't say anything about copying the result back in to x. x.map!(a => a * a).copy(x);
Jul 20 2015
parent reply "Nicholas Wilson" <iamthewilsonator hotmail.com> writes:
On Monday, 20 July 2015 at 14:59:21 UTC, John Colvin wrote:
 On Monday, 20 July 2015 at 14:40:59 UTC, jmh530 wrote:
 [...]
Everything is exactly as I would expect. Lambdas with => are just shorthand that skips the return expression and std.algorithm.each just calls the lambda for each element in x, it doesn't say anything about copying the result back in to x. x.map!(a => a * a).copy(x);
But the lambda takes a ref parameter...
Jul 20 2015
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Monday, 20 July 2015 at 15:08:16 UTC, Nicholas Wilson wrote:
 But the lambda takes a ref parameter...
Yes, but it never writes to it: x.each!((ref a) => a + 1); Instead, this should work: x.each!((ref a) => a = a + 1); ... as a short-hand for: x.each!((ref a) { a = a + 1; });
Jul 20 2015
parent "jmh530" <john.michael.hall gmail.com> writes:
On Monday, 20 July 2015 at 15:12:28 UTC, Marc Schütz wrote:
 On Monday, 20 July 2015 at 15:08:16 UTC, Nicholas Wilson wrote:
 But the lambda takes a ref parameter...
Yes, but it never writes to it: x.each!((ref a) => a + 1); Instead, this should work: x.each!((ref a) => a = a + 1); ... as a short-hand for: x.each!((ref a) { a = a + 1; });
This works! Thanks.
Jul 20 2015
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 20 July 2015 at 14:40:59 UTC, jmh530 wrote:
 I have found the documentation for each in std.algorithm a bit 
 terse. It seemed like it was an eager version of map, but it 
 seems to be a bit more limited than that.

 In particular, the documentation says that if you can mutate 
 the value in place, then you can call each on it. The first 
 thing I noticed is that this works easiest (beyond in place 
 operators) when you're using a void function and taking the 
 input you want to change as ref. This is what I did in the foo 
 and bar functions below. However, it's not the same thing as 
 just applying the function. In the baz function, I mutate the 
 value and then return a different value. Using baz with each 
 doesn't change the value by 2, only by 1.

 What really confused me is that I can't use a lambda with each 
 in a similar way as map. I think this is because the lambdas 
 I'm using really aren't void functions. The part after the => 
 is basically a return statement, so I'm not really mutating 
 anything in place. Is there any way to do this with lambdas or 
 are void functions required?
"a += 1" in D is an expression that first mutates a and then returns a. Therefore, you can write this lamda: (ref a) => a += 1 And it should work fine with `each`. The expanded version that this desugars to is: int function(ref int a) { return a += 1; } On the other hand, however, a + 1 is an expression that does not mutate a. It just returns the value of a with 1 added to it. Therefore, `(ref a) => a + 1` cannot work, as it does not actually modify a. The best way to think of it is as if the body of your lambda is being executed in a `foreach` loop. If you translate some of your examples, it should become obvious as to what the result is. x.each!((ref a) => a++) becomes foreach (ref a; x) { a++; } And, of course, the answer is x == [2, 3, 4].
Jul 20 2015
prev sibling next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
Also, map is lazy, but each isn't.
Jul 20 2015
prev sibling parent reply "sigod" <sigod.mail gmail.com> writes:
On Monday, 20 July 2015 at 14:40:59 UTC, jmh530 wrote:
 I have found the documentation for each in std.algorithm a bit 
 terse. It seemed like it was an eager version of map, but it 
 seems to be a bit more limited than that.
Why are you trying to use `each` in place which belongs to `map`?
Jul 20 2015
parent "jmh530" <john.michael.hall gmail.com> writes:
On Monday, 20 July 2015 at 21:24:37 UTC, sigod wrote:
 On Monday, 20 July 2015 at 14:40:59 UTC, jmh530 wrote:
 I have found the documentation for each in std.algorithm a bit 
 terse. It seemed like it was an eager version of map, but it 
 seems to be a bit more limited than that.
Why are you trying to use `each` in place which belongs to `map`?
More just out of my own curiosity of trying to understand how it worked.
Jul 20 2015