我读了这篇文章,我发现它很有趣.
总结那些不想阅读整篇文章的人.作者实现了一个名为Curry的高阶函数(由我重构而没有他的内部类):
public static Func> Curry (this Func fn) { Func , Func >> curry = f => x => y => f(x, y); return curry(fn); }
这使我们能够采用像F(x,y)这样的表达式.
Funcadd = (x, y) => x + y;
并以F.Curry()(x)(y)方式调用它;
这部分我理解,我觉得它很酷,以一种令人讨厌的方式.我无法解决的问题是这种方法的实际用途.何时何地需要这种技术以及可以从中获得什么?
提前致谢.
编辑:在最初的3个响应之后,我理解增益将是在某些情况下,当我们从curried创建一个新函数时,一些参数不会被重新评估.我在C#中进行了这个小测试(请记住,我只对C#实现感兴趣,而不是一般的咖喱理论):
public static void Main(string[] args) { Funcconcat = (a, b) => a.ToString() + b.ToString(); Func > concatCurry = concat.Curry(); Func curryConcatWith100 = (a) => concatCurry(100)(a); Console.WriteLine(curryConcatWith100(509)); Console.WriteLine(curryConcatWith100(609)); } public struct Int { public int Value {get; set;} public override string ToString() { return Value.ToString(); } public static implicit operator Int(int value) { return new Int { Value = value }; } }
在连续2次调用curryConcatWith100时,对值100的ToString()求值被调用两次(每次调用一次),所以我在这里看不到任何评估增益.我错过了什么吗?
Currying用于将具有x参数的函数转换为具有y参数的函数,因此可以将其传递给需要具有y参数的函数的另一个函数.
例如,Enumerable.Select(this IEnumerable
使用带有1个参数的函数.Math.Round(double, int)
是一个有2个参数的函数.
您可以使用currying将Round
函数"存储" 为数据,然后将该curried函数传递给Select
类似的函数
FuncroundFunc = (n, p) => Math.Round(n, p); Func roundToTwoPlaces = roundFunc.Curry()(2); var roundedResults = numberList.Select(roundToTwoPlaces);
这里的问题是,还有匿名委托,这使得currying多余.事实上,匿名代表是一种讨论形式.
FuncroundToTwoPlaces = n => Math.Round(n, 2); var roundedResults = numberList.Select(roundToTwoPlaces);
甚至只是
var roundedResults = numberList.Select(n => Math.Round(n, 2));
考虑到某些函数语言的语法,Currying是解决特定问题的一种方法.使用匿名委托和lambda运算符,.NET中的语法更简单.
更容易首先考虑fn(x,y,z).这可以通过使用fn(x,y)进行计算,给出一个只接受一个参数z的函数.无论单独使用x和y需要做什么,都可以通过返回函数所持有的闭包来完成和存储.
现在,您使用z的各种值多次调用返回的函数,而不必重新计算所需的x和y部分.
编辑:
咖喱有两个理由.
正如Cameron所说,将一个带有2个参数的函数转换为仅占用1的函数.使用参数调用此curried函数的结果与使用2个参数调用原始函数相同.
由于Lambda存在于C#中,因此它们的价值有限,因为它们无论如何都能提供这种效果.虽然你使用的是C#2,但你问题中的Curry函数有更大的价值.
咖喱的另一个原因就像我之前所说的那样.当最终参数被提供给curried函数时,允许复杂/昂贵的操作被分阶段并重复使用几次.
这种类型的currying在C#中是不可能实现的,它确实需要一种功能性语言,可以原生地模拟它的任何功能来实现.
通过你提到的Curry参数减少在C#2中是有用的,但由于Lambdas在C#3中被大幅度减值.