5

我正在观看 Misko Hevery 的关于干净代码的演讲,他提到尝试编写一个不包含 if 语句的程序(嗯,尽可能少)以模拟... Smalltalk 或类似的语言,其中多态性优于内联条件行为。

就我有限的理解而言,函数式编程对于像我这样的只有命令式的程序员来说很难——因为我们的状态改变方法无法在函数式程序中表达。一个函数只接受一个值并返回一个值,对状态一无所知。

我还看到 JS 被誉为能够支持功能模型。

那么是否有一组简单的限制,类似于我的第一段,这将使我能够以我熟悉和喜爱的语言尝试功能范式 - 而不是学习一门全新的语言(我最终会这样做,但我想要现在就尝试这种精神)?

4

2 回答 2

5

“函数式编程”一词有两种含义。

第一个含义是程序操作函数的能力。并非所有语言都可以做到这一点,但 javascript 是可以做到的语言之一。可以将函数分配给变量、将函数传递给参数和返回函数的语言称为函数式编程语言,因此 javascript 是函数式的。

从这个意义上说,如果您查看任何普遍使用回调的现代 javascript 代码,那么您已经在进行函数式编程。

函数式编程的第二个含义是编程风格,其中程序组合的主要方法是函数而不是变量。从这个意义上说,通过避免变量赋值和循环结构(使用递归代替),几乎任何语言都可以以函数式风格使用。

当您查看函数式社区时,他们所说的函数式是第一个含义加上第二个含义的非常强大的版本——也就是说,变量不仅被避免,而且被禁止。Haskell 等语言没有变量的概念。为了处理像 I/O 这样的副作用和可变状态,他们使用了一个叫做 monads 的概念。

你不必走那么远。像 Lisp 和 Forth 这样的经典函数式语言允许使用变量。你只需要尽可能避免它们。

Lisp 和 Forth 风格的函数式编程主要由处理列表/数组驱动,而无需为临时变量分配任何内容。对某些人来说,这种风格更容易阅读。在命令式风格中你会这样做:

var a = [1,2,3];
var b = 0;
for (var i=0;i=a.length;i++) {
    b += a[i] * 2;
}
// result is in b

在功能风格中,你会这样做:

[1,2,3].
    map(function(x){return x*2}).
    reduce(function(x,y){return x+y},0);

从概念上讲,函数式风格看起来像是在对数组应用过滤器,而不是遍历数组。如果您曾经使用过类似的命令行工具,grep您会发现这个概念非常熟悉。

请注意,我们根本没有在函数式​​风格中引入任何变量赋值。

函数式风格中的三个核心数组方法/函数是mapreducefilter. 使用它们,您可以避免 90% 的 for 循环。

于 2013-10-27T20:57:54.113 回答
2

好问题。

要获得深入的答案,请查看 John Hughes 的这篇经典(而且很棒)论文——为什么函数式编程很重要

首先,Hughes 解释了函数式编程不是关于什么,并引用了 FP 支持者使用的一些弱论点。好东西(但这里引用太长了)。

其次,休斯解释了 FP 是什么:

现在普遍认为模块化设计是成功编程的关键,最近的语言,如 Modula-II [6] 和 Ada [5] 包括专门设计用于帮助提高模块化的特性。但是,有一个非常重要的点经常被忽略。在编写模块化程序来解决问题时,首先将问题划分为子问题,然后解决子问题,最后组合解决方案。划分原始问题的方式直接取决于将解决方案粘合在一起的方式。因此,为了提高在概念上模块化问题的能力,必须在编程语言中提供新的粘合剂。复杂的范围规则和单独编译的规定仅有助于文书细节——它们永远不会对模块化做出重大贡献。

我们将在本文的其余部分讨论函数式语言提供了两种新的、非常重要的粘合剂。我们将给出一些可以以新方式模块化并因此可以简化的程序示例。这是函数式编程强大的关键——它允许改进模块化。这也是函数式程序员必须努力的目标——更小、更简单、更通用的模块,用我们将要描述的新粘合剂粘合在一起。

(强调我的)

所以回到最初的问题,为了在 Javascript 中执行 FP,您需要通过实现单独的模块来构建程序,然后将它们粘合在一起。Javascript 带有一些很好的胶水,您可以自己构建更多的胶水——查看组合器。

您应该尽量避免使用胶水来组合模块化代码的功能,例如:

  • 可变状态——特别是如果它是全局的
  • 语句 - 您不能将while-loops 作为函数参数传递
  • 某些类型的语法,例如运算符或属性访问——您不能分配+给变量或将其作为参数传递

(当然,这些问题可以在一定程度上得到缓解——查看 Javascript FP 库以获取示例。)

另一方面,不是函数的特性——比如类、对象、继承、原型等——并不一定会阻止你使用 Javascript 的粘合剂,所以从 FP 的角度来看,没有理由不去使用它们。

于 2013-10-28T17:00:17.200 回答