scurry

Curry and Partial Application for C# functions and actions.


Project maintained by sgaliamov Hosted on GitHub Pages — Theme by mattgraham

Currying C# functions and actions

If you are here, you probably know what Curry and Partial Application are. This library contains extensions for all standard Func<> and Action<> delegates.

Build status codecov NuGet Badge

Features

  1. Supports all standard Func<> and Action<> delegates.
  2. Currying and uncurrying.
  3. Partial Application with special spacer.
  4. Pipe and Compose helper functions.
  5. All code is auto generated and covered by unit tests.
  6. .NET Standard 1.0+, .NET Standard 2.0+.
  7. No external dependencies.

Examples

Lets say you have the next function:

Func<int, int, int, int> Multiply = (a, b, c) => a * b * c;

Partial Application

The library contains Partial Application extensions for all standard delegates:

Func<int, int, int> multiply2Partial = Multiply.Partial(2, 3);
int result = multiply2Partial(4); // 24

In case if you know the values for some arguments in advance you can use the spacer:

using static SCurry.Spacer;
...
Func<int, int, int> multiply2Partial = Multiply.Partial(_, _, 2); // or Multiply.Partial(1, _, 2) or Multiply.Partial(_, 2)
int result = multiply2Partial(3, 4); // 24

At the moment you can use the spacer for delegates with up to 8 parameters. Making it more makes the library ridiculous big.

If you need to make partial call on a function with more that 8 parameters you can combine two Partial functions:

var partial = Add16.Partial(1, 2, 3, 4, 5, 6, 7, 8).Partial(_, 8, 7, 6, 5, 4, 3, 2);
var result = partial(1); // 72

Curry

To curry use Curry extension:

Func<int, Func<int, Func<int, int>>> multiplyCurried = Multiply.Curry();
int result = multiplyCurried(2)(3)(4); // 24

You can combine it with gapped version of Partial extension to get more flexibility:

using static SCurry.Spacer;
...
Func<int, int> multiply2 = Multiply.Partial(_, _, 2).Curry();
int result = multiply6(5)(6); // 30

Uncurry

After curry you may want to get normal function back:

Func<int, int> multiply2curryed = Multiply.Partial(_, _, 2).Curry();
Func<int, int, int> multiply2 = multiply2curryed.Uncurry();
int result = multiply2(3, 4); // 24

Pipe and Compose

You can chain functions with Pipe helper:

using static SCurry.Piper;
...
Func<int, int, int, int> Multiply = (a, b, c) => a * b * c;
Func<int, int> CurryedAdd2WithGap = TestFunctions.Add2.Partial(_, 2).Curry();
Func<int, Func<int, int>> CurryedPartialMultiplyBy3 = Multiply.Partial(_, _, 3).Curry();
Func<int, Func<int, Func<int, int>>> CurryedAdd3 = TestFunctions.Add3.Curry();

var piped = Pipe(
    CurryedAdd2WithGap,
    CurryedPartialMultiplyBy3(1),
    CurryedAdd3(3)(1)
);

var result = piped(0); // 10

Or Compose them to evaluate functions in reverse order:

using static SCurry.Composer;
...
var piped = Compose(
    CurryedAdd2WithGap,
    CurryedPartialMultiplyBy3(1),
    CurryedAdd3(3)(1)
);

var result = piped(0); // 14