A currying function

Artur Skawina art.08.09 at gmail.com
Tue Jun 19 05:52:20 PDT 2012


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


More information about the Digitalmars-d mailing list