digitalmars.D.learn - passing a variadic parameter to randomSample
- forkit (19/19) Jan 25 2022 so I'm trying to write (or rather learn how to write) a 'variadic
- vit (28/47) Jan 25 2022 `r` is not input range, try this:
- forkit (22/22) Jan 25 2022 On Tuesday, 25 January 2022 at 11:50:08 UTC, vit wrote:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (14/18) Jan 25 2022 Watch out though: The compiler will compile a different function per set...
- forkit (24/24) Jan 25 2022 On Tuesday, 25 January 2022 at 22:07:43 UTC, Ali Çehreli wrote:
- forkit (6/6) Jan 25 2022 On Tuesday, 25 January 2022 at 22:35:29 UTC, forkit wrote:
- H. S. Teoh (22/24) Jan 25 2022 D has several flavors of variadics:
- H. S. Teoh (7/22) Jan 25 2022 I think with -dip1000 the compiler should refuse to compile the code if
- Stanislav Blinov (4/9) Jan 26 2022 Huh? Perhaps you meant "for ("hello") vs. ("hello", "world")"?
- =?UTF-8?Q?Ali_=c3=87ehreli?= (5/15) Jan 26 2022 You're right. I mistakenly assumed it would be the same as
- =?UTF-8?Q?Ali_=c3=87ehreli?= (11/12) Jan 26 2022 I am still wrong there. It is inconceivable to instantiate the following...
- WebFreak001 (43/62) Jan 25 2022 With R... each value could be of different type, so passing
- WebFreak001 (44/82) Jan 25 2022 With R... each value could be of different type, so passing
so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // --
Jan 25 2022
On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote:so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // --`r` is not input range, try this: ```d module test; import std; string RandomChoice1(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).randomSample(1, rnd).front; } string RandomChoice2(R...)(R r) nogc { auto rnd = MinstdRand0(unpredictableSeed); switch(rnd.front % R.length){ static foreach(enum I, alias arg; r){ case I: return arg; } default: assert(0, "no impl"); } } void main() { writeln( RandomChoice1("typeA", "typeB", "typeC") ); writeln( RandomChoice2("typeA", "typeB", "typeC") ); } ```
Jan 25 2022
On Tuesday, 25 January 2022 at 11:50:08 UTC, vit wrote:thanks. problem solved (providing all parameters are of the same type). // --- module test; import std; auto RandomChoice(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).randomSample(1, rnd).front; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); writeln( RandomChoice(5, 8, 2) ); writeln( RandomChoice(100.05, 110.8, 109.54) ); //writeln( RandomChoice("typeA", 5, 100.14) ); // nope. they all need to be of the same type. writeln( RandomChoice("typeA", 5.to!string, 100.14.to!string) ); } //--
Jan 25 2022
On 1/25/22 13:55, forkit wrote:auto RandomChoice(R...)(R r)Watch out though: The compiler will compile a different function per set of values. For example, there will be separate RandomChoice instances for ("hello") vs. ("world"). D has a simple variadic parameter syntax as well: auto RandomChoice(R)(R[] r...){ auto rnd = MinstdRand0(unpredictableSeed); return only(r).randomSample(1, rnd).front;Which makes that simpler as well because being a slice, r is already a range. And there is choice(): return r.choice(rnd); Something is very important though: The 'r' slice is short-lived; it does not live in dynamic memory. RandomChoice() should not save it for later use nor return it. (The compiler may have protection against that; I am not sure.) Ali
Jan 25 2022
On Tuesday, 25 January 2022 at 22:07:43 UTC, Ali Çehreli wrote:thanks. makes it even shorter and simpler :-) // -- module test; safe: import std; auto RandomChoice(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).choice(rnd); } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); writeln( RandomChoice(5, 8, 2) ); writeln( RandomChoice(1.3, 5.09, 8, 2) ); writeln( RandomChoice(100.05, 110.8, 109.54) ); //writeln( RandomChoice("typeA", 5, 100.14) ); // nope. some issue with mixing strings with numeric types writeln( RandomChoice("typeA", 5.to!string, 100.14.to!string) ); // NOTE: This registers with -profile=gc } // --
Jan 25 2022
On Tuesday, 25 January 2022 at 22:35:29 UTC, forkit wrote:I should point out (to anyone looking at that code I posted), that it's easier, and makes more sense, to just write: writeln( ["typeA", "typeB", "typeC"].choice ); ... but my main focus here, was learning about variadic template functions.
Jan 25 2022
On Tue, Jan 25, 2022 at 10:48:26PM +0000, forkit via Digitalmars-d-learn wrote: [...]... but my main focus here, was learning about variadic template functions.D has several flavors of variadics: 1) C-style variadics (not type-safe, not recommended): int func(int firstArgc, ...) 2) D-style type-safe variadics (non-templated): int func(int[] args...) All arguments must be of the same type, and the function receives them as an array of that type, so .length can be used to ensure you don't overrun the array. 3) Variadic template functions: int func(Args...)(Args args) Arguments can be of any type, the type can be obtained with Args[i]. (Not to be confused with lowercase args[i], which gives you the argument value itself.) The most flexible of the lot, but may also lead to template bloat if used excessively (one instantiation is generated for every different combination of argument types). There's also the lazy variant of (2) with delegates, but I've never used them before. T -- An elephant: A mouse built to government specifications. -- Robert Heinlein
Jan 25 2022
On Tue, Jan 25, 2022 at 02:07:43PM -0800, Ali Çehreli via Digitalmars-d-learn wrote: [...]auto RandomChoice(R)(R[] r...)I think with -dip1000 the compiler should refuse to compile the code if you try to save a slice of r past the function body. T -- Philosophy: how to make a career out of daydreaming.{ auto rnd = MinstdRand0(unpredictableSeed); return only(r).randomSample(1, rnd).front;Which makes that simpler as well because being a slice, r is already a range. And there is choice(): return r.choice(rnd); Something is very important though: The 'r' slice is short-lived; it does not live in dynamic memory. RandomChoice() should not save it for later use nor return it. (The compiler may have protection against that; I am not sure.)
Jan 25 2022
On Tuesday, 25 January 2022 at 22:07:43 UTC, Ali Çehreli wrote:On 1/25/22 13:55, forkit wrote:Huh? Perhaps you meant "for ("hello") vs. ("hello", "world")"? Because it would be the same instantiation for a single string argument :)auto RandomChoice(R...)(R r)Watch out though: The compiler will compile a different function per set of values. For example, there will be separate RandomChoice instances for ("hello") vs. ("world").
Jan 26 2022
On 1/26/22 02:20, Stanislav Blinov wrote:On Tuesday, 25 January 2022 at 22:07:43 UTC, Ali Çehreli wrote:You're right. I mistakenly assumed it would be the same as RandomChoice(string a, string b)(). But still, as you show, the instantiations could be too many for R... AliOn 1/25/22 13:55, forkit wrote:Huh? Perhaps you meant "for ("hello") vs. ("hello", "world")"? Because it would be the same instantiation for a single string argument :)auto RandomChoice(R...)(R r)Watch out though: The compiler will compile a different function per set of values. For example, there will be separate RandomChoice instances for ("hello") vs. ("world").
Jan 26 2022
On 1/26/22 07:44, Ali Çehreli wrote:the instantiations could be too many for R...I am still wrong there. It is inconceivable to instantiate the following template for the same type (e.g. string) from "too many" places in a program: auto RandomChoice(R...)(R r) { // ... } There may be a few instantiations that call it with 1, 2, 4... maybe 10 arguments? But that would be it... Oh! Unless there is some code generation. :) Ali
Jan 26 2022
On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote:so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // --With R... each value could be of different type, so passing `RandomChoice("typeA", 4)` would break the current code. I think there are 2 different ways that can solve this elegantly: 1) restrict the parameters to all be the same parameter type: ```d string RandomChoice(T)(T[] r...) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } ``` and code compiles with no changes. Instead of using .to!string you could also return the parameter type itself if you want to get the value itself: ```d T RandomChoice(T)(T[] r...) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).front; } ``` 2) generate a random number between 0 and `r.length`, add a switch case and dynamically generate a case for each number (static foreach) and return the processed value using .to!string: ```d string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); switch (uniform(0, R.length, rnd)) { static foreach (i, value; r) { case i: // this code is duplicated for each parameter // use this if you want to support different argument types return value.to!string; } default: assert(false); } } ```
Jan 25 2022
On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote:so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // --On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote:so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // --With R... each value could be of different type, so passing `RandomChoice("typeA", 4)` would break the current code. I think there are 2 different ways that can solve this elegantly: 1) restrict the parameters to all be the same parameter type: ```d string RandomChoice(T)(T[] r...) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } ``` and code compiles with no changes. Instead of using .to!string you could also return the parameter type itself if you want to get the value itself: ```d T RandomChoice(T)(T[] r...) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).front; } ``` 2) generate a random number between 0 and `r.length`, add a switch case and dynamically generate a case for each number (static foreach) and return the processed value using .to!string: ```d string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); switch (uniform(0, R.length, rnd)) { static foreach (i, value; r) { case i: // this code is duplicated for each parameter // use this if you want to support different argument types return value.to!string; } default: assert(false); } } ```
Jan 25 2022