5

我知道柯里化的概念和使用方法,但我想知道它在实践中的价值是什么?

4

3 回答 3

5

正如相关问题所涵盖的,实际使用柯里化函数?,人们重视并使用柯里化的原因有很多,包括:

  • 改进代码重用——特殊情况函数只是部分应用(和柯里化)的通用函数
  • 提高代码可读性——map (+2)比阅读更容易map (\x -> x + 2)
  • 改进的性能——柯里化可以明显地产生某些特化,一个好的编译器会为你生成特化的版本
  • 有趣——更简单的代码,更漂亮的代码让生活更愉快。
于 2011-07-07T18:37:25.847 回答
2

我发现的真正好处:

  • 更少的错误- 通过函数组合来组合代码往往会产生比命令式控制流更正确的代码。例如,如果您使用“map”而不是“for 循环”,则可以消除许多“off by one”索引错误的风险

  • 更好的并发性——你用纯的、无副作用的函数创建的代码是自动线程安全的。将其与不可变的持久数据结构结合起来,您就有了编写健壮并发代码的好方法。Clojure 对此特别有用 - 请参阅http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey

  • 更简洁和易于管理的代码- 在我完全不科学的分析中,功能代码似乎比命令式 OOP 代码短得多。随着程序变得越来越大,这种好处往往会更加明显。我认为这有几个原因:

    • 函数式语言的语法往往非常简洁。例如,Haskell 和各种 Lisps 都有非常简单和优雅的语法
    • 函数式语言倾向于鼓励(高阶函数的)组合,而不是将程序的各个部分“粘合”在一起。因此,您避免了许多其他范例中固有的大量样板。
    • 与组合点相关,我发现在函数式语言中应用 DRY 原则更容易。如果你看到一个常见的模式,几乎总是可以很容易地将它提取到一个更高阶的函数(或者如果你是一个 Lisper 的宏)中,这样你就可以在其他地方使用它。
  • 可测试性——当您主要使用纯函数编写代码时,编写健壮的测试非常容易。

当然,有一些缺点可以抵消这一点:

  • 写起来更难——你需要更多的思维敏捷性,因为你需要在脑海中掌握相当复杂的抽象概念。如果您是受过训练的数学家(我是),这会有所帮助,但我仍然发现编写函数式代码比 OOP 更难。
  • 有一些性能开销——函数式语言使用各种结构,这必然意味着一定程度的开销。虽然这可以通过好的编译器变得非常小,但它永远无法完全消除。
  • 库/工具 支持——这几乎完全是由于 OOP 平台和工具更加成熟,但这仍然是一个问题。从长远来看,这不会成为问题,但我发现的最佳解决方案是使用 Clojure,它可以从大多数 Java 平台库和工具中受益。
于 2011-07-06T08:14:15.720 回答
1

我会说这有点像一次又一次

在 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 循环。这类似于程序代码中的柯里化。这里的优势很明显。

柯里化是一个重要的理论概念,但在实践中,这是优势。

其实我记得有一次用 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 语言,没有宏技巧等。函数式风格,有点像柯里化。这里的好处是你可以一目了然地看到测试用例是什么。data_set类似——它将其参数绑定到另一个获取数据的函数:for_all执行 thunk,检查谓词并清理。整齐的。

于 2011-07-06T08:26:13.813 回答