C#中Currying的优势是什么?
在curry函数上实现部分函数应用的优点是什么?
答案 0 :(得分:12)
Currying实际上并不是很好 与我们做的不同 计算一些给定的函数 在一张纸上的价值观。
使用函数
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)。每次更换 导致a内的函数 功能。随着我们顺序取代 每一个论点,我们都在讨论 功能变得更简单,更简单 原版的版本。最终, 我们最终得到了一系列功能 在lambda演算中,每个 函数只接受一个参数,和 多参数函数通常是 以咖喱形式表示。
currying的实际动机 经常是这些功能 通过提供一些但不是全部来获得 curried函数的参数 (通常称为部分应用)是 有用;例如,许多语言 有一个类似的功能或操作员 加一。 Currying让它变得容易 定义这些功能。
答案 1 :(得分:12)
如果你的问题是如何在C#中实现currying,这里有一个例子
public Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(Func<T1, T2, TResult> func)
{
return p1 => p2 => func(p1, p2);
}
Currying可以用任何支持闭包(lambdas)的语言实现,并且对于部分函数应用程序很有用,比如UI编程,其中没有接收到执行函数所需的所有输入,因此已经传递了curry函数接收到的输入。
答案 2 :(得分:1)
Currying在C#中的优势在于它允许C#开发人员以函数式编程风格开发。
想想LINQ。 LINQ查询允许您将方法作为参数传递:
someCollection.Where(x => x.someVal == 1);
x.someVal == 1
被评估为函数,然后Where
在自己的执行中使用返回值。
这是大多数.NET 3开发人员熟悉的一个例子,但很少有人意识到他们正在涉及函数编程。没有Curry的能力,LINQ是不可能的。
...希望能够弥补我的智慧评论。
答案 3 :(得分:1)
我发现部分函数应用程序,而不是currying,在我想重用代码时非常有用。
很明显,由于currying和partial function apply的定义似乎变得模糊,因此通过部分函数应用我的意思是使用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);
}
答案 4 :(得分:-1)
简单的Currying将是
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
}
}
}