digitalmars.D.learn - map question
- forkit (21/21) Jan 22 2022 trying to make sense of the below:
- Stanislav Blinov (25/46) Jan 22 2022 No, it's not the same. 'Tis not really a "map question", looks
- forkit (11/11) Jan 22 2022 On Saturday, 22 January 2022 at 19:55:43 UTC, Stanislav Blinov
- Stanislav Blinov (4/16) Jan 23 2022 Using `iota` here incurs additional computation and argument
- Siarhei Siamashka (39/42) Jan 23 2022 Isn't this normally a compiler's job to eliminate all unused
- Stanislav Blinov (12/54) Jan 23 2022 It is the programmer's job long before it is the compiler's. It
- =?UTF-8?Q?Ali_=c3=87ehreli?= (10/15) Jan 22 2022 Somebody else mentioned this before but none of the programs we've seen
trying to make sense of the below: // --- module test; import std; void main() { auto rnd = Random(unpredictableSeed); int howManyTimes = 5; // ok - using 'e =>' makes sense writeln(howManyTimes.iota.map!(e => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); // ok - though using 'howManyTimes =>' doesn't make much sense?? writeln(howManyTimes.iota.map!(howManyTimes => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); // NOT ok - using '5 =>' - but isn't this effectively the same as above line? //writeln(howManyTimes.iota.map!(5 => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); } // ---
Jan 22 2022
On Saturday, 22 January 2022 at 19:32:07 UTC, forkit wrote:trying to make sense of the below: // --- module test; import std; void main() { auto rnd = Random(unpredictableSeed); int howManyTimes = 5; // ok - using 'e =>' makes sense writeln(howManyTimes.iota.map!(e => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); // ok - though using 'howManyTimes =>' doesn't make much sense?? writeln(howManyTimes.iota.map!(howManyTimes => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); // NOT ok - using '5 =>' - but isn't this effectively the same as above line? //writeln(howManyTimes.iota.map!(5 => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); } // ---No, it's not the same. 'Tis not really a "map question", looks more like a question about https://dlang.org/spec/expression.html#function_literals (see In the second case, you're defining a lambda with single parameter named `howManyTimes`, which is not at all related to your local variable of the same name. Third case is invalid, as you're effectively trying to do this: auto func(T)(T 5) { return rnd.dice(0.6, 1.4); } Which, of course, doesn't make any sense, does it? :) Given your use case (call a function N times), I think `generate` would be more appropriate here: ```d import std.random; import std.stdio; import std.range : generate, take; void main() { auto rnd = Random(unpredictableSeed); int howManyTimes = 5; generate!(() => rnd.dice(0.6, 1.4)).take(howManyTimes).writeln; } ```
Jan 22 2022
On Saturday, 22 January 2022 at 19:55:43 UTC, Stanislav Blinov wrote:thanks for the explanation. That really helped :-) writeln( generate!(() => dice(0.6, 1.4)).take(howManyTimes) ); [1, 1, 1, 1, 0] (or after reading Ali's response - getting rid of rnd, and using _ ) writeln( howManyTimes.iota.map!(_ => dice(0.6, 1.4)) ); [1, 0, 1, 1, 1] They produce exactly the same thing, so I guess it comes down to personal choice now.
Jan 22 2022
On Saturday, 22 January 2022 at 23:54:27 UTC, forkit wrote:On Saturday, 22 January 2022 at 19:55:43 UTC, Stanislav Blinov wrote:Using `iota` here incurs additional computation and argument copies that are actually never used, i.e. wasted work. So I'd say go with `generate`, as that seems the intent.thanks for the explanation. That really helped :-) writeln( generate!(() => dice(0.6, 1.4)).take(howManyTimes) ); [1, 1, 1, 1, 0] (or after reading Ali's response - getting rid of rnd, and using _ ) writeln( howManyTimes.iota.map!(_ => dice(0.6, 1.4)) ); [1, 0, 1, 1, 1] They produce exactly the same thing, so I guess it comes down to personal choice now.
Jan 23 2022
On Sunday, 23 January 2022 at 09:08:46 UTC, Stanislav Blinov wrote:Using `iota` here incurs additional computation and argument copies that are actually never used, i.e. wasted work. So I'd say go with `generate`, as that seems the intent.Isn't this normally a compiler's job to eliminate all unused computations and copies? ```D auto foobar1(size_t n) { return n.iota.map!(_ => 123).array; } auto foobar2(size_t n) { return generate!(() => 123).take(n).array; } ``` LDC with "-O -release" command line options generates pretty much identical code for foobar1 and foobar2 (I'm only showing the main loop, but the rest is also the same): ``` 20: 48 39 c8 cmp %rcx,%rax 23: 74 18 je 3d <_D2zz7foobar1FNaNbNfmZAi+0x3d> 25: c7 04 8a 7b 00 00 00 movl $0x7b,(%rdx,%rcx,4) 2c: 48 83 c1 01 add $0x1,%rcx 30: 48 39 cb cmp %rcx,%rbx 33: 75 eb jne 20 <_D2zz7foobar1FNaNbNfmZAi+0x20> ``` ``` 20: 48 39 c8 cmp %rcx,%rax 23: 74 18 je 3d <_D2zz7foobar2FNaNbNfmZAi+0x3d> 25: c7 04 8a 7b 00 00 00 movl $0x7b,(%rdx,%rcx,4) 2c: 48 83 c1 01 add $0x1,%rcx 30: 48 39 cb cmp %rcx,%rbx 33: 75 eb jne 20 <_D2zz7foobar2FNaNbNfmZAi+0x20> ``` Do you have a better example to demonstrate `generate`'s superiority?
Jan 23 2022
On Sunday, 23 January 2022 at 09:38:57 UTC, Siarhei Siamashka wrote:On Sunday, 23 January 2022 at 09:08:46 UTC, Stanislav Blinov wrote:It is the programmer's job long before it is the compiler's. It can do wonders on your "minimal" code but it's not its job to read your mind.Using `iota` here incurs additional computation and argument copies that are actually never used, i.e. wasted work. So I'd say go with `generate`, as that seems the intent.Isn't this normally a compiler's job to eliminate all unused computations and copies?```D auto foobar1(size_t n) { return n.iota.map!(_ => 123).array; } auto foobar2(size_t n) { return generate!(() => 123).take(n).array; } ``` LDC with "-O -release" command line options generates pretty much identical code for foobar1 and foobar2 (I'm only showing the main loop, but the rest is also the same): ``` 20: 48 39 c8 cmp %rcx,%rax 23: 74 18 je 3d <_D2zz7foobar1FNaNbNfmZAi+0x3d> 25: c7 04 8a 7b 00 00 00 movl $0x7b,(%rdx,%rcx,4) 2c: 48 83 c1 01 add $0x1,%rcx 30: 48 39 cb cmp %rcx,%rbx 33: 75 eb jne 20 <_D2zz7foobar1FNaNbNfmZAi+0x20> ``` ``` 20: 48 39 c8 cmp %rcx,%rax 23: 74 18 je 3d <_D2zz7foobar2FNaNbNfmZAi+0x3d> 25: c7 04 8a 7b 00 00 00 movl $0x7b,(%rdx,%rcx,4) 2c: 48 83 c1 01 add $0x1,%rcx 30: 48 39 cb cmp %rcx,%rbx 33: 75 eb jne 20 <_D2zz7foobar2FNaNbNfmZAi+0x20> ``` Do you have a better example to demonstrate `generate`'s superiority?Try actual work instead of returning a literal :) Like e.g. calling dice(50, 50). One thing to note though - `generate` will always eagerly call its function at least once. Which of course should also be considered in choosing the desired implementation. I.e. if your `n` comes from user and is allowed to be 0, then `generate` becomes an inferior choice.
Jan 23 2022
On 1/22/22 11:32, forkit wrote:trying to make sense of the below:The generate() solution shown by Stanislav Blinov is suitable here.auto rnd = Random(unpredictableSeed);Somebody else mentioned this before but none of the programs we've seen so far seemed to need a special random number generator. So, the default one, which is already randomized, would suffice. Just drop the line above.// ok - using 'e =>' makes sense writeln(howManyTimes.iota.map!(e => rnd.dice(0.6, 1.4)).format!"%(%s,%)");When there is a syntactic need for a variable but that variable is not used, the idiomatic way of naming that variable is '_': howManyTimes.iota.map!(_ => dice(0.6, 1.4)) (Note: I did not write rnd.dice.) Ali
Jan 22 2022