Skip to content

Instantly share code, notes, and snippets.

@battermann
Created June 10, 2015 10:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save battermann/fb42befda2ad2bbe9449 to your computer and use it in GitHub Desktop.
Save battermann/fb42befda2ad2bbe9449 to your computer and use it in GitHub Desktop.
Function composition in C#
using System;
using System.Collections.Generic;
using NUnit.Framework;
using System.Linq;
namespace function_composition_in_csharp
{
// The NUnit Nuget package is required for this
// To install NUnit, run the following command in the Package Manager Console
// PM> Install-Package NUnit -Version 2.6.4
[TestFixture]
public class FunctionCompositionExamples
{
[Test]
public void Function_composition()
{
var f = new Func<string, IEnumerable<string>>(s => s.Split(new[] { ' ' }));
var g = new Func<string, string>(s => s.ToUpper());
var h = f.Compose(g);
Assert.That(h("foo bar"), Is.EqualTo(new[] { "FOO", "BAR" }));
}
[Test]
public void Currying_and_partial_application()
{
// first we have to create curried versions of add and multiply
var add = new Func<int, int, int>((x, y) => x + y).Curry();
var multiply = new Func<int, int, int>((x, y) => x * y).Curry();
var add1AndMultiplBy2 = multiply(2).Compose(add(1));
Assert.That(add1AndMultiplBy2(3), Is.EqualTo(8));
}
[Test]
public void Without_currying()
{
var add = new Func<int, int, int>((x, y) => x + y);
var multiply = new Func<int, int, int>((x, y) => x * y);
// composing partially applied uncurried functions
var add1AndMultiplBy2 = new Func<int, int>(x => multiply(2, x)).Compose(new Func<int, int>(x => add(x, 1)));
Assert.That(add1AndMultiplBy2(3), Is.EqualTo(8));
}
[Test]
public void Reverse_words()
{
var reverseWords = Unwords
.Compose(Map.Curry()(Reverse))
.Compose(Words);
Assert.That(reverseWords("Foo bar"), Is.EqualTo("ooF rab"));
}
[Test]
public void Pipelining()
{
Func<string, string> reverseWords =
s => s.Words()
.Select(StringExtensions.Reverse)
.Unwords();
Assert.That(reverseWords("Foo bar"), Is.EqualTo("ooF rab"));
}
[Test]
public void Forward_composition()
{
var f = new Func<string, string>(s => s.ToUpper());
var g = new Func<string, IEnumerable<string>>(s => s.Split(new[] { ' ' }));
var h = f.ComposeForward(g);
Assert.That(h("foo bar"), Is.EqualTo(new[] { "FOO", "BAR" }));
}
static readonly Func<string, IEnumerable<string>> Words =
s => s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
static readonly Func<Func<string, string>, IEnumerable<string>, IEnumerable<string>> Map =
(f, list) => list.Select(f);
static readonly Func<string, string> Reverse =
s => new String(s.Reverse().ToArray());
static readonly Func<IEnumerable<string>, string> Unwords =
list => String.Join(" ", list);
}
public static class FuncExtensions
{
public static Func<T1, T3> Compose<T1, T2, T3>(this Func<T2, T3> f, Func<T1, T2> g)
{
return x => f(g(x));
}
public static Func<T1, T3> ComposeForward<T1, T2, T3>(this Func<T1, T2> f, Func<T2, T3> g)
{
return x => g(f(x));
}
}
public static class StringExtensions
{
public static IEnumerable<string> Words(this string s)
{
return s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
}
public static string Reverse(this string s)
{
return new String(s.ToCharArray().Reverse().ToArray());
}
public static string Unwords(this IEnumerable<string> words)
{
return String.Join(" ", words);
}
}
public static class FunctionExtensions
{
public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
{
return x1 => x2 => func(x1, x2);
}
public static Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func)
{
return x1 => x2 => x3 => func(x1, x2, x3);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, TResult>>>> Curry<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> func)
{
return x1 => x2 => x3 => x4 => func(x1, x2, x3, x4);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, TResult>>>>> Curry<T1, T2, T3, T4, T5, TResult>(this Func<T1, T2, T3, T4, T5, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => func(x1, x2, x3, x4, x5);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, TResult>>>>>> Curry<T1, T2, T3, T4, T5, T6, TResult>(this Func<T1, T2, T3, T4, T5, T6, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => func(x1, x2, x3, x4, x5, x6);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, TResult>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => func(x1, x2, x3, x4, x5, x6, x7);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, TResult>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => func(x1, x2, x3, x4, x5, x6, x7, x8);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, Func<T9, TResult>>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => x9 => func(x1, x2, x3, x4, x5, x6, x7, x8, x9);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, Func<T9, Func<T10, TResult>>>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => x9 => x10 => func(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, Func<T9, Func<T10, Func<T11, TResult>>>>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => x9 => x10 => x11 => func(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, Func<T9, Func<T10, Func<T11, Func<T12, TResult>>>>>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => x9 => x10 => x11 => x12 => func(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, Func<T9, Func<T10, Func<T11, Func<T12, Func<T13, TResult>>>>>>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => x9 => x10 => x11 => x12 => x13 => func(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, Func<T9, Func<T10, Func<T11, Func<T12, Func<T13, Func<T14, TResult>>>>>>>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => x9 => x10 => x11 => x12 => x13 => x14 => func(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, Func<T9, Func<T10, Func<T11, Func<T12, Func<T13, Func<T14, Func<T15, TResult>>>>>>>>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => x9 => x10 => x11 => x12 => x13 => x14 => x15 => func(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, Func<T5, Func<T6, Func<T7, Func<T8, Func<T9, Func<T10, Func<T11, Func<T12, Func<T13, Func<T14, Func<T15, Func<T16, TResult>>>>>>>>>>>>>>>> Curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> func)
{
return x1 => x2 => x3 => x4 => x5 => x6 => x7 => x8 => x9 => x10 => x11 => x12 => x13 => x14 => x15 => x16 => func(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment