Поддерживает ли C # композицию функций? - PullRequest
25 голосов
/ 10 марта 2011

В последней версии C # я могу сделать что-то вроде this ?

Мне кажется, что linq - самый близкий, но это цепочка, а не функциональная композиция, верно?

Ответы [ 8 ]

15 голосов
/ 10 марта 2011
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))));
14 голосов
/ 10 марта 2011

Я не дал компилятору проверить это, но это должно быть возможно:

Func<T3,T1> my_chain(Func<T2,T1> f1, Func<T3,T2> f2)
{
    return (x=> f2(f1(x)));
}
10 голосов
/ 10 марта 2011

В C # нет специального оператора / «синтаксического сахара» (однако в F # вы бы использовали оператор >>).

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Автор сообщения . Он предлагает такую ​​конструкцию в 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)));
6 голосов
/ 10 марта 2011

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 голосов
/ 10 марта 2011

Это не так красиво, но вы могли бы сделать:

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

Или, если вы хотите что-то более composit-y (которое действует на массив на месте):

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);
3 голосов
/ 10 марта 2011

Больше, чем в Linq, его делегаты и лямбда-выражения / операторы похожи на цепочку.

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

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

Определение, приведенное в ссылке:

Состав функцииакт конвейерной передачи результата одной функции на вход другой, создание совершенно новой функции.

И c - это явно новая функция, которая вызывает цепочку a и b.

1 голос
/ 10 марта 2011

Нет, не говоря уже об определении ваших собственных общих Compose<T, U...>() функций. C # не имеет встроенных функций, чтобы помочь вам с этим. (Частичное применение также не выполняется.)

0 голосов
/ 11 июня 2016

Пример композиции функции в 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
...