我知道这个概念以及如何使用currying,但我想知道它在实践中的价值是什么?
答案 0 :(得分:5)
正如相关问题所涵盖的那样,Practical use of curried functions?,人们重视和使用它的原因有很多,包括:
map (+2)
比map (\x -> x + 2)
答案 1 :(得分:2)
我发现了真正的好处:
减少错误 - 按功能组合编写代码往往会产生比命令控制流更正确的代码。例如,如果您使用“map”而不是“for loops”,则可以消除许多“逐个”索引错误的风险
更好的并发性 - 使用纯的,无副作用的函数创建的代码自动是线程安全的。将此与不可变的持久数据结构结合起来,您就可以编写强大的并发代码。 Clojure特别适合这一点 - 见http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey
更简洁,更易于管理的代码 - 在我完全不科学的分析中,功能代码似乎要比命令式OOP代码短得多。随着计划变得更大,收益往往更加明显。我认为有几个原因:
可测试性 - 当您主要使用纯函数编写代码时,编写健壮的测试非常容易。
当然有一些缺点:
答案 2 :(得分:1)
我会说它有点像Once and Only Once
在C / C ++中,我发现自己编写的代码如
configure_grid (grid, first_column, last_column, action) {
for (i = first_column; i <= last_column; ++i)
// ...
}
configure_grids (action) {
congifure_grid (alpha, first_alpha, last_alpha, action);
congifure_grid (beta, first_beta, last_beta, action);
}
而不是为每个alpha和beta写一次for-loop。这与程序代码中的讨论相似。这里的优势很明显。
Currying是一个重要的理论概念,但在实用术语中,这是优势。
事实上,我记得曾经在C中编写一个测试套件,它有点像这样:
typedef bool (*predicate) (const type *);
const char * argument;
bool do_foo (const type * t) {
return bar (t, argument);
}
bool do_baz (const type * t) {
return bap (t, argument);
}
predicate foo (const char * arg) {
argument = arg;
return do_foo;
}
predicate baz (const char * arg) {
argument = arg;
return do_baz;
}
assert (for_all (data_set("alpha"), foo ("abc")));
assert (for_all (data_set("beta"), baz ("def")));
这完全是纯粹的C,没有宏观技巧等。功能风格和类似于currying。这里的优点是您可以准确地看到测试用例的确切内容。 data_set
类似 - 它将其参数绑定到另一个获取数据的函数:for_all
执行thunk,检查谓词,并清理。整齐。