Skip to content

Instantly share code, notes, and snippets.

@cameronpresley
Last active December 19, 2017 12:51
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 cameronpresley/1bd47ea84edad7d6052b69b71b0d2def to your computer and use it in GitHub Desktop.
Save cameronpresley/1bd47ea84edad7d6052b69b71b0d2def to your computer and use it in GitHub Desktop.
Function Extensions with Examples
public class Example
{
public void DemonstrateMap()
{
Func<int, string> tostring = s => s.ToString();
4.Map(tostring);
}
public void DemonstrateCompose()
{
Func<int, List<int>> toList = a => new List<int> {a};
Func<List<int>, List<string>> toStringList = a => a.Select(x => x.ToString()).ToList();
Func<int, List<string>> numberToStringList = toList.Compose(toStringList);
42.Map(numberToStringList);
}
public void DemonstrateDo()
{
4.Map(x => x.ToString()).Do(Console.WriteLine);
}
public void DemonstrateApply()
{
Func<int, int, int> add = (a, b) => a + b;
Func<int, int> add2 = add.Apply(2);
add2.Apply(4).Do(Console.WriteLine);
}
public void DemonstrateIdentity()
{
Console.WriteLine(4.Map(FunctionExtensions.Identity) == 4);
}
public void DemonstrateNoOp()
{
4.Do(FunctionExtensions.NoOp).Do(Console.WriteLine);
}
}
public static class FunctionExtensions
{
public static U Map<T, U>(this T value, Func<T, U>func)
{
return func(value);
}
public static Func<T, T2> Compose<T, T1, T2>(this Func<T, T1>first, Func<T1, T2>second)
{
return x => second(first(x));
}
public static T Do<T>(this T value, Action<T>action)
{
action(value);
return value;
}
public static Func<T1> Apply<T, T1>(this Func<T, T1>func, T value)
{
return () => func(value);
}
public static Func<T1, T2> Apply<T, T1, T2>(this Func<T, T1, T2> func, T value)
{
return a => func(value, a);
}
public static Func<T1, T2, T3> Apply<T, T1, T2, T3>(this Func<T, T1, T2, T3>func, T value)
{
return (a, b) => func(value, a, b);
}
public static Func<T1, T2, T3, T4> Apply<T, T1, T2, T3, T4>(this Func<T, T1, T2, T3, T4>func, T value)
{
return (a, b, c) => func(value, a, b, c);
}
public static T Identity<T>(T value)
{
return value;
}
public static void NoOp<T>(this T value)
{
}
}
@IEvangelist
Copy link

Nice!! These are pretty slick. I was playing around with it some then I discovered something interesting. While you can use local functions as arguments to methods expecting variations of delegates, i.e.; Action, Action<in T, ...>, Func<out TResult>, Func<in T, ..., out TResult>, etc. You cannot use them as arguments into an extension method where they would be implicitly converted to the delegate.

That is VERY odd. For example, this works:

    public void OhMyGod()
    {
        int sum(int x, int y) => x + y;
        var result = InvokeSum(sum, 7, 7);
    }

    public int InvokeSum(Func<int, int, int> func, int x, int y) => func(x, y);

I was trying to change your example usages to leverage local functions, so instead of this:

public void DemonstrateCompose()
{
    Func<int, List<int>> toList = a => new List<int> {a};
    Func<List<int>, List<string>> toStringList = a => a.Select(x => x.ToString()).ToList();
    Func<int, List<string>> numberToStringList = toList.Compose(toStringList);

    42.Map(numberToStringList);
}

Do this (notice the use of local functions rather than Func<int, List<int>> and Func<List<int>, List<string>>):

public void DemonstrateCompose()
{
    List<int> toList(int a) => new List<int> { a };
    List<string> toStringList(List<int> a) => a.Select(x => x.ToString()).ToList();
    Func<int, List<string>> numberToStringList = toList.Compose(toStringList);

    42.Map(numberToStringList);
}

There is a compiler error.

Error CS0119 'toList(int)' is a method, which is not valid in the given context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment