Created
June 10, 2015 10:34
-
-
Save battermann/fb42befda2ad2bbe9449 to your computer and use it in GitHub Desktop.
Function composition in C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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