C#是否支持功能组合?

时间:2011-03-10 18:29:54

标签: c# .net haskell composition

在最新版本的C#中,我可以执行this之类的操作吗?

我觉得linq是最接近的,但那是链接,而不是功能组合,对吗?

8 个答案:

答案 0 :(得分:15)

public static class Extensions
{
    public static Func<T, TReturn2> Compose<T, TReturn1, TReturn2>(this Func<TReturn1, TReturn2> func1, Func<T, TReturn1> func2)
    {
        return x => func1(func2(x));
    }
}

用法:

Func<int, int> makeDouble = x => x * 2;
Func<int, int> makeTriple = x => x * 3;
Func<int, string> toString = x => x.ToString();
Func<int, string> makeTimesSixString = toString.Compose(makeDouble).Compose(makeTriple);

//Prints "true"
Console.WriteLine(makeTimesSixString (3) == toString(makeDouble(makeTriple(3))));

答案 1 :(得分:13)

我没有让编译器检查这个,但这应该是可能的:

Func<T3,T1> my_chain(Func<T2,T1> f1, Func<T3,T2> f2)
{
    return (x=> f2(f1(x)));
}

答案 2 :(得分:10)

在C#中没有特定的运算符/“语法糖”(但是,在F#中,您将使用>>运算符)。

Matthew Podwysocki对此主题有一个 great blog post 。他在C#中建议了这种结构:

public static class FuncExtensions
{
    public static Func<TSource, TResult> ForwardCompose<TSource, TIntermediate, TResult>(
        this Func<TSource, TIntermediate> func1, Func<TIntermediate, TResult> func2)
    {
        return source => func2(func1(source));
    }
}

Func<Func<int, int>, IEnumerable<int>, IEnumerable<int>> map = (f, i) => i.Select(f);
Func<Func<int, bool>, IEnumerable<int>, IEnumerable<int>> filter = (f, i) => i.Where(f);
Func<int, Func<int, int, int>, IEnumerable<int>, int> fold = (s, f, i) => i.Aggregate(s, f);

// Compose together
var mapFilterFold = map.Apply(x => x * x * x)
    .ForwardCompose(filter.Apply(x => x % 3 == 0))
    .ForwardCompose(fold.Apply(1, (acc, x) => acc * x));
Console.WriteLine(mapFilterFold(Enumerable.Range(1, 10)));

答案 3 :(得分:6)

C#没有一流的支持,但实施起来并不是特别困难。你只需要编写很多重载。

public static class Composition
{
    public static Func<T2> Compose<T1, T2>(Func<T1> f1, Func<T1, T2> f2)
    {
        return () => f2(f1());
    }

    public static Func<T1, T3> Compose<T1, T2, T3>(Func<T1, T2> f1, Func<T2, T3> f2)
    {
        return v => f2(f1(v));
    }
}

答案 4 :(得分:4)

它不是那么漂亮,但你可以做到:

Func<IEnumerable<T>, IEnumerable<T>> desort = l => l.OrderBy(i => i).Reverse();

或者,如果你想要更复杂的东西(它在阵列上起作用):

Action<int[]> desort = a => Array.Reverse(Array.Sort(a));

假设存在这些方法......但语法应该是正确的。

然后您可以通过以下方式使用它(假设您使用了上面的第一种方法):

var arr = { 2,8,7,10,1,9,5,3,4,6 };
var desortedArr = desort(arr);

答案 5 :(得分:3)

不仅仅是Linq,它是委托,还有与链接类似的lambda表达式/语句。

Func<int, string> a = p => p.ToString();
Func<string, string> b = p => "|" + p + "|";

Func<int, string> c = p => b(a(p));

链接中给出的定义是:

  

函数组合是将一个函数的结果流水线化为另一个函数的输入,创建一个全新的函数。

而且c显然是一个链接调用ab的新功能。

答案 6 :(得分:1)

不,不缺少定义自己的通用Compose<T, U...>()函数。 C#没有内置功能来帮助您解决这个问题。 (它也没有部分应用。)

答案 7 :(得分:0)

C#中的函数组合示例

f(x)°g(x)

Func<int, int> f = x => x + 2;
Func<int, int> g = x => 3 * x;

Func<int, int> b = x => f(g(x));

int result = b(2); //Result is 8