Currying在C#中的优势是什么? (实现部分function)

Currying在C#中的优势是什么?

在curry函数上实现部分函数应用的优点是什么?

Currying在C#中的优势在于它允许C#开发人员以函数式编程风格开发。

想想LINQ。 LINQ查询允许您将方法作为参数传递:

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

x.someVal == 1被评估为函数,然后Where在其自己的执行中使用返回值。

这是大多数.NET 3开发人员熟悉的示例,但很少有人意识到他们正在涉及函数编程。 没有Curry的能力,LINQ是不可能的。

…希望能够弥补我的智慧评论。

来自维基百科

实际上,当我们在一张纸上计算某些给定值的函数时,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

在纸面上,使用经典符号,只是我们似乎同时完成所有这些。 但是,实际上,当在一张纸上替换参数时,它是按顺序(即部分)完成的。 每次替换都会导致函数内的函数。 当我们按顺序替换每个参数时,我们将函数简化为更简单和更简单的原始版本。 最终,我们最终得到了lambda演算中的一系列函数,其中每个函数只接受一个参数,而多参数函数通常以curryforms表示。

currying的实际动机是,通常通过向curried函数(通常称为部分应用程序)提供一些但不是所有参数而获得的函数是有用的; 例如,许多语言都具有类似于plus_one的函数或运算符。 Currying可以轻松定义这些function。

如果你的问题是如何在C#中实现currying,这是一个例子

 public Func> Curry(Func func) { return p1 => p2 => func(p1, p2); } 

Currying可以用支持闭包(lambdas)的任何语言实现,并且对于部分函数应用程序很有用,例如在UI编程中,其中没有接收到执行函数所需的所有输入,因此传递已经接收到的输入的curry函数在里面。

我发现部分函数应用程序,而不是currying,在我想重用代码时很有用。

需要明确的是,由于currying和partial函数应用的定义似乎变得模糊,因此通过部分函数应用我的意思是使用具有N个参数的函数,并将其转换为具有N-1个参数的函数。

特别是,在编写unit testing时它非常方便。 由于我将编写数百个unit testing,因此我尝试尽可能重用测试代码。 所以我可能有一个通用的测试方法,它将委托给我想要测试的方法,加上该方法的一些参数和预期的结果。 常用的测试方法将使用提供的参数执行测试中的方法,并且将有几个断言将结果与预期结果进行比较。

当我想测试一个参数比传递给公共测试方法的委托更多的方法时,就会出现问题。 我可以编写另一个与第一个相同的常用测试方法,除了使用具有不同签名的委托。 然而,这似乎重复了我自己。 为了避免编写这样的重复代码,我可以使用部分函数应用程序将一个委托(例如两个参数)转换为一个带有单个参数的委托。 现在我可以使用我的常用测试方法来测试带有一个或两个参数的方法。

这是我用来修复传入的委托的一个参数的辅助方法之一:

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

一个简单的Currying将会

 using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { Func 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 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 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 } } }