C#是否支持功能组合?

Joa*_*nge 29 .net c# haskell composition

在C#的最新版本,我可以这样做这个

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

Dav*_*vy8 17

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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))));
Run Code Online (Sandbox Code Playgroud)


Doc*_*own 14

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

public static Func<T3,T1> my_chain<T1, T2, T3>(Func<T2,T1> f1, Func<T3,T2> f2)
{
    return x => f2(f1(x));
}
Run Code Online (Sandbox Code Playgroud)

  • +1现在这是一个非常有用的实现.我会交换类型以保持顺序:`Func <T1,T3>组成(Func <T2,T3> f,Func <T1,T2> g){return(x => f(g(x)) )}`. (3认同)
  • @pst可悲的是,我非常确定.NET的"标准"方法中有一半以上有多个参数.微软的那些坏人创造了一个真正地狱般的框架!他们应该为Haskell学习!一个参数对每个人都足够!! :-) (2认同)
  • @Joan:基本上,`fxyz =(x + y)*z`变为`fx =(\ y - >(\ z - >))`.因此,对于您应用的每个参数,您将获得一个闭包,该闭包是接近实际结果的一步/参数,但在计算结果之前将等待剩余的参数.也称为"部分应用".您可以使用支持闭包的每种语言自己完成,但只有语言帮助才能实现. (2认同)

Max*_*dov 12

在C#中没有特定的操作符/"语法糖"(但是,在F#中,您将使用>>运算符).

Matthew Podwysocki 有一篇关于这个主题的文.他在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)));
Run Code Online (Sandbox Code Playgroud)


Cha*_*ion 7

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));
    }
}
Run Code Online (Sandbox Code Playgroud)