www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to repeat a function call?

reply =?ISO-8859-1?Q?Simen_Kj=E6r=E5s?= <simen.kjaras gmail.com> writes:
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
Apr 02 2014
next sibling parent reply "w0rp" <devw0rp gmail.com> writes:
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.
Apr 02 2014
parent "monarch_dodra" <monarchdodra gmail.com> writes:
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))); }
Apr 02 2014
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
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.
Apr 02 2014
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
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*.
Apr 02 2014
parent =?UTF-8?B?U2ltZW4gS2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
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
Apr 02 2014