Func<T1～T16,TResult>に対する拡張メソッド（部分適用・カリー化・遅延評価）


# Func に対する拡張メソッド #

汎用デリゲート Func に対する拡張メソッドを作成しました。

```C#
Func<TResult>
Func<T, TResult>
Func<T1, T2, TResult>
Func<T1, T2, T3, TResult>
（省略）
Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>
```

.NET 4.0 では最大16個の引数を持つデリゲートが定義されているわけですが、全ての Func に対応したソースコードがネット上に見つからなかったので作成しました。GutHub にアップしてあります。（かなりニッチな内容で、需要はあまりないかもしれませんが）
[【GitHub】mxProject/Misc](https://github.com/mxProject/Misc/blob/master/source/DelegateExtension.cs)

## カリー化 ##

`Func<T1, T2, T3, TResult>`を`Func<T1, Func<T2, Func<T3, TResult>>>`に変換します。

```C#:カリー化
/// <summary>
/// Converts the specified delegate to a curried delegate.
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="T3"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
public static Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func)
{
    return arg1 => arg2 => arg3 => func(arg1, arg2, arg3);
}

// 例
internal static DateTime GetDate(int year, short month, byte day)
{
    return new DateTime(year, month, day);
}

Func<int, short, byte, DateTime> f = GetDate;
Func<int, Func<short, Func<byte, DateTime>>> curry = f.Curry();

var result1 = GetDate(2018, 2, 28);
var result2 = curry(2018)(2)(28);

```

## カリー化の解除 ##

`Func<T1, Func<T2, Func<T3, TResult>>>`を`Func<T1, T2, T3, TResult>`に変換します。

```C#:カリー化の解除
/// <summary>
/// Converts the specified curried delegate to a uncurried delegate.
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="T3"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
public static Func<T1, T2, T3, TResult> Uncurry<T1, T2, T3, TResult>(this Func<T1, Func<T2, Func<T3, TResult>>> func)
{
    return (arg1, arg2, arg3) => func(arg1)(arg2)(arg3);
}

// 例
internal static DateTime GetDate(int year, short month, byte day)
{
    return new DateTime(year, month, day);
}

Func<int, short, byte, DateTime> f = GetDate;
Func<int, Func<short, Func<byte, DateTime>>> curry = f.Curry();
Func<int, short, byte, DateTime> uncurry = curry.Uncrry();

var result1 = curry(2018)(2)(28);
var result2 = uncurry(2018, 2, 28);

```

## 遅延評価 ##

引数を与えて`Func<T1, T2, T3, TResult>`を`Func<TResult>`に変換します。引数を与えるだけで実行はされません。

```C#:遅延評価
/// <summary>
/// Converts the specified delegate to a lasy evaluation delegate.
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="func"></param>
/// <param name="arg1"></param>
/// <param name="arg2"></param>
/// <returns></returns>
public static Func<TResult> Lazy<T1, T2, TResult>(this Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
{
    return () => func(arg1, arg2);
}

// 例
internal static DateTime GetDate(int year, short month, byte day)
{
    return new DateTime(year, month, day);
}

Func<int, short, byte, DateTime> f = GetDate;
Func<DateTime> lazy = f.Lazy(2018, 2, 28);

var result1 = GetDate(2018, 2, 28);
var result2 = lazy();

```

## 部分適用 ##

先頭の引数を与えて`Func<T1, T2, T3, TResult>`を`Func<T2, T3, TResult>`に変換します。引数を与えるだけで実行はされません。

```C#:部分適用
/// <summary>
/// Converts the specified delegate to a partial apply delegate.
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="T3"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="func"></param>
/// <param name="arg1"></param>
/// <returns></returns>
public static Func<T2, T3, TResult> Partial<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func, T1 arg1)
{
    return (arg2, arg3) => func(arg1, arg2, arg3);
}

// 例
internal static DateTime GetDate(int year, short month, byte day)
{
    return new DateTime(year, month, day);
}

Func<int, short, byte, DateTime> f = GetDate;
Func<short, byte, DateTime> applyYear = f.Partial(2018);

var result1 = GetDate(2018, 2, 28);
var result2 = applyYear(2, 28);

```

## カリー化後の部分適用 ##

`Func<T1, Func<T2, Func<T3, TResult>>>`に対して何れかの引数を与えて型引数の数を減らします。カリー化解除と共に使うことが多いのではないかと思います。

```C#:カリー化後の部分適用
/// <summary>
/// Converts the specified curried delegate to a partial apply delegate.
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <typeparam name="T3"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
public static Func<T2, Func<T3, Func<T1, TResult>>> Partial<T1, T2, T3, TResult>(this Func<T1, Func<T2, Func<T3, TResult>>> func)
{
    return arg2 => arg3 => arg1 => func(arg1)(arg2)(arg3);
}

// 例
internal static DateTime GetDate(int year, short month, byte day)
{
    return new DateTime(year, month, day);
}

Func<int, short, byte, DateTime> f = GetDate;
Func<int, Func<short, Func<byte, DateTime>>> curry = f.Curry();
Func<int, Func<short, DateTime>> applyDay = curry.Partial().Partial()(28);
Func<int, short, DateTime> applyDayUncurry = applyDay.Uncurry();

var result1 = GetDate(2018, 2, 28);
var result2 = applyDay(2018)(2);
var result3 = applyDayUncurry(2018, 2);

```


## 参考にした記事 ##

[【koropicot's blog】C#で部分適用](http://koropicot.hateblo.jp/entry/2013/09/08/185849)