Skip to content

Instantly share code, notes, and snippets.

@JakobOvrum
Last active October 17, 2015 16:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JakobOvrum/8b2cd11b911079735b14 to your computer and use it in GitHub Desktop.
Save JakobOvrum/8b2cd11b911079735b14 to your computer and use it in GitHub Desktop.
Curry implementation using structs (efficient but yields unwieldy types)
import std.traits : isFunctionPointer;
private struct Curry(uint n, F...)
if(F.length == 1)
{
import std.traits : ParameterTypeTuple;
alias Args = ParameterTypeTuple!F;
static if(is(F[0]))
private F[0] func;
else
alias func = F[0];
private Args[0 .. n] args;
static if(n == Args.length - 1)
{
auto ref opCall(Args[n] lastArg)
{
return func(args, lastArg);
}
}
else
{
auto opCall(Args[n] nextArg)
{
Curry!(n + 1, F) next;
static if(is(F[0]))
next.func = func;
next.args[0 .. n] = args;
next.args[n] = nextArg;
return next;
}
}
}
auto curry(F)(F func)
if(isFunctionPointer!F || is(F == delegate))
{
Curry!(0, F) result;
result.func = func;
return result;
}
auto curry(alias func)()
{
Curry!(0, func) result;
return result;
}
unittest
{
static long sum(int a, int b, int c)
{
return a + b + c;
}
assert(curry(&sum)(1)(2)(3) == 6);
assert(curry!sum()(1)(2)(3) == 6);
static string repeat(string a, int n)
{
string result;
foreach(immutable i; 0 .. n)
result ~= a;
return result;
}
assert(curry(&repeat)("foo")(3) == "foofoofoo");
assert(curry!repeat()("foo")(3) == "foofoofoo");
int outer = 42;
assert(curry((int inner) => outer - inner)(2) == 40);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment