В чем преимущество Currying в С#? (достижение частичной функции)

В чем преимущество Currying в С#?

В чем преимущество достижения частичного применения функции для функции curried?

Ответы

Ответ 1

Преимущество Currying в С# заключается в том, что он позволяет разработчикам С# развиваться в стиле функционального программирования.

Подумайте о LINQ. Запрос LINQ позволяет вам передать метод в качестве параметра:

someCollection.Where(x => x.someVal == 1);

x.someVal == 1 получает оценку как функцию, а затем Where использует возвращаемое значение в своем собственном выполнении.

Это пример того, что большинство разработчиков .NET 3 знакомы, но мало кто понимает, что они занимаются программированием функций. Без возможности Curry LINQ будет невозможно.

... hopefull, который компенсирует мой комментарий к умной заднице.

Ответ 2

От Wikipedia

Каррирование на самом деле не очень отличается от того, что мы делаем, когда мы вычислить функцию для некоторого заданного значения на листе бумаги.

Возьмем функцию f(x,y) = y / x

     

Чтобы оценить f(2,3), сначала замените x на 2.

     

Так как результатом является новая функция по y, то эту функцию g (y) можно определить как

     

g(y) = f(2,y) = y / 2

     

Затем, заменив аргумент y на 3,

     

дает результат, g(3) = f(2,3) = 3 / 2.

На бумаге, используя классическую нотацию, это просто то, что мы, кажется, делаем все это на в то же время. Но, фактически, когда заменяя аргументы на кусок бумаги, это делается последовательно (I.e.partially). Каждая замена приводит к функции в пределах функция. Когда мы последовательно заменяем каждый аргумент, мы просматриваем функции в более простой и простой версии оригинала. В итоге, мы заканчиваем цепочкой функций как в лямбда-исчислении, где каждый функция принимает только один аргумент и функции с несколькими аргументами обычно представленный в карри.

Практическая мотивация каррирования что очень часто функции полученных, поставляя некоторые, но не все аргументов для карриной функции (часто называемые частичным применением) полезно; например, на многих языках имеют функцию или оператор, аналогичные плюс один. Каррирование упрощает определить эти функции.

Ответ 3

Если ваш вопрос заключается в том, как реализовать currying на С#, вот пример

public Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(Func<T1, T2, TResult> func)
    {
        return p1 => p2 => func(p1, p2);
    }

Currying может быть реализован на любом языке, который поддерживает замыкания (lambdas), и полезен для приложений с частичным функционалом, например, в программировании пользовательского интерфейса, где все входные данные, необходимые для выполнения функции, не принимаются, поэтому каррическая функция передается с уже полученные входные данные в нем.

Ответ 4

Я нашел приложение частичной функции, в отличие от currying, полезным, когда я хочу повторно использовать код.

Чтобы быть ясными, поскольку определения приложения currying и partial function кажутся размытыми, с помощью приложения частичной функции я подразумеваю использование функции с N параметрами и преобразование ее в функцию с параметрами N-1.

В частности, это было удобно при написании модульных тестов. Поскольку я буду писать сотни модульных тестов, я стараюсь повторно использовать тестовый код, где это возможно. Поэтому у меня может быть общий метод тестирования, который принимает делегат к методу, который я хочу проверить, плюс некоторые параметры этого метода и ожидаемый результат. Общий метод тестирования будет выполнять тестируемый метод с предоставленными параметрами и будет иметь несколько утверждений, сравнивающих результат с ожидаемым результатом.

Проблема возникает, когда я хочу протестировать метод, который имеет больше параметров, чем делегат, передаваемый в общий метод тестирования. Я мог бы написать еще один распространенный метод тестирования, который идентичен первому, кроме того, что делегат имеет другую подпись. Однако это похоже на повторение. Чтобы избежать необходимости писать такой повторяющийся код, я могу использовать приложение частичной функции для преобразования делегата, берущего, скажем, два параметра, в делегат, принимающий один параметр. Теперь я могу использовать свой общий метод тестирования для тестирования методов, которые принимают один или два параметра.

Здесь один из вспомогательных методов, которые я использую, чтобы исправить один из аргументов делегата, который был передан:

/// <summary>
/// Fixes an argument of an action delegate, creating a closure that combines the 
/// delegate and the argument value. 
/// </summary>
/// <returns>An action delegate which takes only one argument.</returns>
public static Action<TIn1> FixActionArgument<TIn1, TIn2>(Action<TIn1, TIn2> action, 
    TIn2 argumentValue)
{
    return in1 => action(in1, argumentValue);
}

Ответ 5

Простая каррировка будет

using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {

            Func<double, double, double, double, double> newTonLaw = (m1, m2, r, g) => ((m1 * m2) / Math.Pow(r,2)) * g;

            // Mass of Earth= 5.98 * 10e24 , Gravitational Constant = 6.6726 * 10e-11
            Func<double, double, double> onEarth = (m2, r) => newTonLaw.Invoke(5.98 * 10e24, m2, r, 6.6726*10e-11);

            // Mass of Moon= 7.348x10e22 , Gravitational Constant = 6.6726 * 10e-11
            Func<double, double, double> onMoon = (m2, r) => newTonLaw.Invoke(7.348 * 10e22, m2, r, 6.6726 * 10e-11);

            Trace.WriteLine(onEarth(70, 6.38 * 10e6)); // result 686.203545562642
            Trace.WriteLine(onMoon(70, 6.38 * 10e6)); // result 8.43181212841855
        }
    }
}