Thread overview
How to repeat a function call?
Apr 02, 2014
Simen Kjærås
Apr 02, 2014
w0rp
Apr 02, 2014
monarch_dodra
Apr 02, 2014
monarch_dodra
Apr 02, 2014
monarch_dodra
Apr 02, 2014
Simen Kjærås
April 02, 2014
I'm trying to create a function that repeats a function call N times. The exact use case is generating an N-dimensional tuple:

import std.typetuple;
import std.typecons;

template Repeat(size_t n, T...) {
    static if (n == 1) {
        alias Repeat = T;
    } else static if (n) {
        alias Repeat = TypeTuple!(Repeat!(n /2, T), Repeat!((n +1)/2, T));
    } else {
        alias Repeat = TypeTuple!();
    }
}

auto fun1(size_t dim, T)(lazy T fn) {
    return tuple(Repeat!(dim, fn));
}

auto fun2(size_t dim, alias fn)() {
    return tuple(Repeat!(dim, fn));
}

void main() {
    int a = 0;
    assert(fun1!3(a++) == tuple(0,1,2));
//    assert(fun2!(3, ()=>a++) == tuple(0,1,2));
}

Now, the call to fun1 works great. But I'd like to specify fn at compile-time, thus doing something more like fun2. fun2 of course, does not work (else why would I ask?).

I tried staticMap'ing a template that calls its parameter over the result of Repeat in Fun2, but that did not work:

template call(alias fn) {
    alias call = TypeTuple!(fn());
}

auto fun3(size_t dim, alias fn)() {
    return tuple(staticMap!(call, Repeat!(dim, fn)));
}

fun3 ends up trying to evaluate the function call at compile-time, and fails because a++ can't be executed until run-time.

Better ideas, please?

--
  Simen
April 02, 2014
tuples are definitely a compile-time job. You could do something like this to build an N tuple by calling a function N many times.

---
import std.typecons;

int foo() {
    return 3;
}

auto initTuple(size_t N, alias func)() {
    string magic() {
        string result = "return tuple(";

        foreach(i; 0..N) {
            result ~= "func(),";
        }

        result ~= ");";

        return result;
    }

    mixin(magic());
}

void main(string[] argv) {
    enum Tuple!(int, int, int) tup = initTuple!(3, foo);
}

---

This just builds the tuple by building up a mixin string which calls the function so many times, with no guarantees about the order of arguments. If you have side-effects in your function though, you probably want to move it runtime anyway and use a range with the 'repeat' function, etc.
April 02, 2014
On Wednesday, 2 April 2014 at 19:02:29 UTC, Simen Kjærås wrote:
> Better ideas, please?
>
> --
>   Simen

I only skimmed through your post, but have you tried taking a look at adjoin? Preferably, the version in head? Something like "adjoin!(repeat!(fun, N))" seems to natively do what you are asking for?

I'll re-read your post later tonight, and if I'm misunderstood, I'll try to provide a better solution.
April 02, 2014
On Wednesday, 2 April 2014 at 19:33:28 UTC, w0rp wrote:
> auto initTuple(size_t N, alias func)() {
>     string magic() {
>         string result = "return tuple(";
>
>         foreach(i; 0..N) {
>             result ~= "func(),";
>         }
>
>         result ~= ");";
>
>         return result;
>     }
>
>     mixin(magic());
> }

auto initTuple(size_t N, alias func)()
{
    return mixin(q{tuple(%-(%s, %))}.format("func".repeat(N)));
}
April 02, 2014
On Wednesday, 2 April 2014 at 19:54:38 UTC, monarch_dodra wrote:
> On Wednesday, 2 April 2014 at 19:02:29 UTC, Simen Kjærås wrote:
>> Better ideas, please?
>>
>> --
>>  Simen
>
> I only skimmed through your post, but have you tried taking a look at adjoin? Preferably, the version in head? Something like "adjoin!(repeat!(fun, N))" seems to natively do what you are asking for?
>
> I'll re-read your post later tonight, and if I'm misunderstood, I'll try to provide a better solution.

Indeed, "assert(adjoin!(Repeat!(3, ()=>a++))() == tuple(0,1,2));" seems to work for me.

That said, while I think the behavior is *defined*, I'm not sure it's *specified*.
April 02, 2014
On 2014-04-02 20:48, monarch_dodra wrote:
> On Wednesday, 2 April 2014 at 19:54:38 UTC, monarch_dodra wrote:
>> On Wednesday, 2 April 2014 at 19:02:29 UTC, Simen Kjærås wrote:
>>> Better ideas, please?
>>>
>>> --
>>>  Simen
>>
>> I only skimmed through your post, but have you tried taking a look at
>> adjoin? Preferably, the version in head? Something like
>> "adjoin!(repeat!(fun, N))" seems to natively do what you are asking for?
>>
>> I'll re-read your post later tonight, and if I'm misunderstood, I'll
>> try to provide a better solution.
>
> Indeed, "assert(adjoin!(Repeat!(3, ()=>a++))() == tuple(0,1,2));" seems
> to work for me.
>
> That said, while I think the behavior is *defined*, I'm not sure it's
> *specified*.

True, in the case of a++, it's probably a bad idea. In my case, the function is uniform(0.0, 1.0, rng), and I'm happy with it simply being random.

Thanks a lot!

--
  Simen