"true" currying [was: Function Currying]
Reiner Pope
reiner.pope at REMOVE.THIS.gmail.com
Wed Nov 15 14:34:39 PST 2006
I've done implemented "true" function currying (according to Bill
Baxter), which converts, say, the function
static int plus(int a, int b, int c)
to
((int delegate(int)) delegate (int)) delegate(int)
(I added extra brackets to perhaps make it more readable)
which means you call it like this:
curried_plus(1)(2)(3) instead of
plus(1,2,3)
and you can do partial function application on it very easily:
auto plus2 = curried_plus(2);
Side note: about half the code I've attached is to determine the type of
the return value. This could be completely avoided if we had type
inference on return values, so
CurriedTypeImpl!(RetType, NewParams).Type bar(MyParam myParam)
could become
auto bar(MyParam myParam)
and the CurriedType2 and CurriedTypeImpl templates could disappear. In
fact, it was with these templates that I spent the most time before they
worked.
Also, typeid's of function/delegate types are printed wrongly (see the
comments in the main function). I don't know whether that is because of
writefln or DMD or what, but it doesn't show the fucntion parameters.
Here's the code:
import std.traits;
import std.stdio;
import std.string;
// For finding the return type
template CurriedTypeImpl(RetType, Params...)
{
static assert(Params.length > 0);
static if (Params.length == 1)
{
alias RetType delegate(Params[0]) Type;
}
else
{
alias CurriedTypeImpl!(RetType, Params[1..length]).Type
delegate(Params[0]) Type;
}
}
// Also for finding the return type
template CurriedType2(DG, KnownParams...)
{
alias ParameterTypeTuple!(DG)[KnownParams.length .. length] Params;
alias ReturnType!(DG) RetType;
alias CurriedTypeImpl!(RetType, Params).Type Type;
}
// Here's where the currying is actually done
CurriedType2!(DG, KnownParams).Type RealCurry(DG, KnownParams...)(DG dg,
KnownParams p)
{
alias ParameterTypeTuple!(dg)[KnownParams.length .. length] Params;
static assert(Params.length > 0);
alias ReturnType!(dg) RetType;
alias Params[1..length] NewParams;
alias Params[0] MyParam;
struct Foo
{
KnownParams p_m;
DG dg_m;
static if (Params.length == 1)
{
RetType bar(MyParam myParam)
{
return dg_m(p_m, myParam);
}
}
else
{
CurriedTypeImpl!(RetType, NewParams).Type bar(MyParam myParam)
{
return RealCurry(dg_m, p_m, myParam);
}
}
}
Foo* f = new Foo;
f.dg_m = dg;
foreach (i, arg; p)
f.p_m[i] = arg;
return &f.bar;
}
void main()
{
static int plus(int x, int y, int z)
{
return x + y + z;
}
auto curried_plus = RealCurry(&plus);
auto plus_two = curried_plus(2);
auto plus_two_plus_three = plus_two(3);
writefln(plus_two_plus_three(4)); // 9
writefln(plus_two(5)(6)); // 13
writefln(typeid(typeof(curried_plus))); // Should print 'int
delegate(int) delegate(int) delegate(int)' but actually prints 'int
delegate() delegate() delegate()'
writefln(typeid(typeof(plus_two_plus_three))); // Should print 'int
delegate(int)' but actually prints 'int delegate()'
writefln(typeid(typeof(plus))); // Should print 'int(int,int,int)'
but actually prints 'int()'
}
Cheers,
Reiner
More information about the Digitalmars-d
mailing list