В чем преимущество карри в C #? (достижение частичной функции) - PullRequest
16 голосов
/ 08 марта 2010

В чем преимущество карри в C #?

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

Ответы [ 5 ]

12 голосов
/ 08 марта 2010

Если ваш вопрос был о том, как реализовать каррирование в C #, вот пример

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

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

12 голосов
/ 08 марта 2010

С Википедия

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

Взять функцию 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). Каждая замена приводит к функции в пределах функция. Как мы последовательно заменяем каждый аргумент, мы карри функционировать все проще и проще версии оригинала. В конце концов, мы в конечном итоге с цепочкой функций, как в лямбда-исчислении, где каждый функция принимает только один аргумент, и функции с несколькими аргументами обычно представлены в карри.

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

1 голос
/ 30 апреля 2013

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

Для ясности, поскольку определения каррирования и частичного применения функции, кажется, размыты, под частичным применением функции я имею в виду получение функции с 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);
}
1 голос
/ 08 марта 2010

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

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

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

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

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

... надеюсь, это восполнит мой умный комментарий.

0 голосов
/ 11 апреля 2015

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

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
        }
    }
}
...