www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - map question

reply forkit <forkit gmail.com> writes:
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
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
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
parent reply forkit <forkit gmail.com> writes:
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
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
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:

 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.
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.
Jan 23 2022
parent reply Siarhei Siamashka <siarhei.siamashka gmail.com> writes:
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
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
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:
 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?
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.
 ```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
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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