Re: passing a variadic parameter to randomSample

2022-01-26 Thread Ali Çehreli via Digitalmars-d-learn

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



Re: passing a variadic parameter to randomSample

2022-01-26 Thread Ali Çehreli via Digitalmars-d-learn

On 1/26/22 02:20, Stanislav Blinov wrote:
> On Tuesday, 25 January 2022 at 22:07:43 UTC, Ali Çehreli wrote:
>> 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").
>
> Huh? Perhaps you meant "for ("hello") vs. ("hello", "world")"? Because
> it would be the same instantiation for a single string argument :)

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...


Ali



Re: passing a variadic parameter to randomSample

2022-01-26 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 25 January 2022 at 22:07:43 UTC, Ali Çehreli wrote:

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").


Huh? Perhaps you meant "for ("hello") vs. ("hello", "world")"? 
Because it would be the same instantiation for a single string 
argument :)





Re: passing a variadic parameter to randomSample

2022-01-25 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jan 25, 2022 at 10:48:26PM +, 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


Re: passing a variadic parameter to randomSample

2022-01-25 Thread forkit via Digitalmars-d-learn

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.




Re: passing a variadic parameter to randomSample

2022-01-25 Thread forkit via Digitalmars-d-learn

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
}

// --




Re: passing a variadic parameter to randomSample

2022-01-25 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jan 25, 2022 at 02:07:43PM -0800, Ali Çehreli via Digitalmars-d-learn 
wrote:
[...]
> 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.)

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.


Re: passing a variadic parameter to randomSample

2022-01-25 Thread Ali Çehreli via Digitalmars-d-learn

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



Re: passing a variadic parameter to randomSample

2022-01-25 Thread forkit via Digitalmars-d-learn

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) 
);

}

//--


Re: passing a variadic parameter to randomSample

2022-01-25 Thread WebFreak001 via Digitalmars-d-learn

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);
}
}
```


Re: passing a variadic parameter to randomSample

2022-01-25 Thread WebFreak001 via Digitalmars-d-learn

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);
}
}
```


Re: passing a variadic parameter to randomSample

2022-01-25 Thread vit via Digitalmars-d-learn

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") );
}
```