C# 中的正确柯里化
给定一个方法 DoSomething
,它接受一个(无参数)函数并以某种方式处理它。 有没有比下面的代码片段更好的方法来为带有参数的函数创建“重载”?
public static TResult DoSomething<TResult>(Func<TResult> func)
{
//call func() and do something else
}
public static TResult DoSomething<T0, TResult>(
Func<T0, TResult> func,
T0 arg0)
{
return DoSomething(() => func(arg0));
}
public static TResult DoSomething<T0, T1, TResult>(
Func<T0, T1, TResult> func,
T0 arg0, T1 arg1)
{
return DoSomething(arg => func(arg, arg1), arg0);
}
public static TResult DoSomething<T0, T1, T2, TResult>(
Func<T0, T1, T2, TResult> func,
T0 arg0, T1 arg1, T2 arg2)
{
return DoSomething(arg => func(arg, arg1, arg2), arg0);
}
Given a method DoSomething
that takes a (parameterless) function and handles it in some way. Is there a better way to create the "overloads" for functions with parameters than the snippet below?
public static TResult DoSomething<TResult>(Func<TResult> func)
{
//call func() and do something else
}
public static TResult DoSomething<T0, TResult>(
Func<T0, TResult> func,
T0 arg0)
{
return DoSomething(() => func(arg0));
}
public static TResult DoSomething<T0, T1, TResult>(
Func<T0, T1, TResult> func,
T0 arg0, T1 arg1)
{
return DoSomething(arg => func(arg, arg1), arg0);
}
public static TResult DoSomething<T0, T1, T2, TResult>(
Func<T0, T1, T2, TResult> func,
T0 arg0, T1 arg1, T2 arg2)
{
return DoSomething(arg => func(arg, arg1, arg2), arg0);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
编辑:正如评论中所指出的,这是部分应用而不是柯里化。 我写了一篇博客文章来阐述我对差异的理解< /a>,人们可能会觉得有趣。
好吧,这并不是特别不同 - 但我会将柯里化部分与“调用 DoSomething”部分分开:
然后:
这样您就可以在其他情况下重用柯里化代码 - 包括您不想调用新函数的情况-立即返回代表。 (例如,您可能想稍后对其进行更多柯里化。)
EDIT: As noted in comments, this is partial application rather than currying. I wrote a blog post on my understanding of the difference, which folks may find interesting.
Well, it's not particularly different - but I'd separate out the currying part from the "calling DoSomething" part:
Then:
That way you can reuse the currying code in other situations - including cases where you don't want to call the newly-returned delegate immediately. (You might want to curry it more later on, for example.)
@Jon Skeet 的答案是正确的,但是手工编写所有可能的过载是疯狂的,所以你可以使用像 这样的库Curryfy 可以为你完成这项工作。 Curryfy lib 特别公开了 Curry、UnCurry 和 ApplyPartial 扩展方法,并具有大量重载。
The @Jon Skeet answer is right, but write by hand all possibles overload is something insane, so you can use a lib like Curryfy that do this job for you. Curryfy lib particularly exposes Curry, UnCurry and ApplyPartial extension methods, with a lot of overloads.
下面是允许使用
dynamic
编写无限调用函数的方法(如 js 中的 Curry):如果您像这样调用它
Sum(2)(3)(4)(10)输出将是:
Here is the method that allows to write unlimited calls of functions using
dynamic
(like Curry in js):If you call it like this
Sum(2)(3)(4)(10)
the output will be:柯里化被定义为将多个参数放入一组接受一个参数的系列中。
我创建了一组使用 lambda 运算符进行柯里化并链接它们的辅助方法。 我费心创建了最多四个参数的辅助方法,因为我们看到参数越多辅助方法变得越压倒性,但它们的模式是相同的。
考虑以下 C# 中的柯里化扩展方法:
以下是测试上述柯里化辅助扩展方法的一组方法。
下面的 main 方法测试了上面方法的柯里化:
我们定义的方法会在传入所有参数时被调用,我们可以选择是一次传入一个参数还是同时一个一个传入多个参数如main方法所示。
这是我们得到的输出,我在 Linqpad 7 中测试了上面的代码:
扩展方法看起来有点麻烦,但我记得见过一些参考源代码定义了最多 16 个带重载参数的泛型方法,这应该涵盖大多数情况。 在此示例中,您至少可以使用链式 lambda 运算符对最多四个参数进行柯里化重载。
Currying is defined as taking multiple arguments into a set of series which accept one argument.
I have created a set of helper methods for currying using lambda operator and chaining them. I have bothered to create helper methods up to four arguments, as we see the helper methods gets more overwhelming the more arguments we get but the pattern of them is the same.
Consider the following extension methods for currying in C#:
Here are a set of methods to test out the currying helper extension methods above.
The following main method tests the currying of the methods above:
The methods we defined will be called when ALL parameters are passed in and we can choose if we pass in one argument at a time or pass in multipe arguments one by one at the same time as shown in the main method.
Here is the output we get, I tested the code above inside Linqpad 7:
The extension methods looks a bit cumbersome but I recall having seen some reference source code defined generic methods up to 16 arguments with overloads, which should cover most cases. In this example you at least have the curry overloads for up to four arguments, using chained lambda operators.