On 06/18/12 22:24, bearophile wrote:
> I think std.functional.curry is badly named because I think it's a "partial 
> application" (I suggest to rename it).
> In Haskell and Scala currying is built-in, this is Haskell, shell (ghci):
> 
> Prelude> let foo x y z = x * 2 + y * 3 + y * 5
> Prelude> let foo1 = foo 5
> Prelude> let foo2 = foo1 4
> Prelude> foo2 3
> 42

> So I've written a D version of it below, not tested much. I have not 
> translated the C++11 version. This was quite easy to write, and much simpler 
> and shorter than the C++11 version (but maybe this misses something, this is 
> just a first draft). This kind of stuff was quite longer to do in D1, but now 
> with CTFE on strings ops, defining one or more inner static functions that 
> build a string at compile-time, it's quite easy. Now I don't need lot of 
> templates to do this.
> 
> There are two alternative designs, curry1 seems a bit more elegant, but if 
> you want to use it in-place it forces you to add a () at the beginning, 
> that's not nice and intuitive. So probably curry2 is better.
[...]
> I think this code induces the creation of heap allocated closures, so 
> probably a more efficient version is needed:

I'm not really sure when you'd want to use this in D.
But, just to be able to say "Real Programmers don't use mixins": :)

   static struct curry(alias F) {
      import std.traits;
      ParameterTypeTuple!F args;
      template opCall1(size_t N=0) {
         auto ref opCall1(ParameterTypeTuple!F[N] a) {
            auto p = (cast(Unqual!(typeof(a))*)&args[N]);
            *p = a;
            static if (N==args.length-1)
               return F(args);
            else
               return &opCall1!(N+1);
         }
      }
      alias opCall1!() opCall;
      static curry opCall() { curry c; return c; }
   }
   //...    
   double foo(immutable int x, in float y, short z=5) pure nothrow {
      return x * 2 + y * 3 + y * 5;
   }
    
   auto cf = curry!foo();
   auto c2 = cf(5)(4);
   writeln(c2(3));
   curry!foo cf2;
   writeln(cf2(5)(4)(3));
   writeln(curry!foo()(5)(4)(3));


The empty parens could be omitted, but you'd need a compiler with full
property support for that (and of course would have to wrap this in a
function). No heap allocations, the resulting code could be better
though.

> So this version doesn't handle ref arguments.

Yeah, this one doesn't either; iterating and checking every arg would
probably be necessary.

artur

Reply via email to