是否有一组限制可用于模拟JavaScript中的函数式编程

Is there a set of restrictions I can use to simulate functional programming in JavaScript?

本文关键字:JavaScript 模拟 用于 编程 函数 一组 是否      更新时间:2023-09-26

我正在看 Misko Hevery 关于干净代码的演讲,他提到试图编写一个没有 if 语句的程序(好吧,尽可能少的人)以模拟工作......Smalltalk 或一些这样的语言,其中多态性优先于内联条件行为。

就我有限的

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

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

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

术语"函数式编程"有两个含义。

第一个含义是程序操作函数的能力。并非所有语言都可以做到这一点,但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 循环。

好问题。

有关深入的答案,请查看John Hughes的这篇经典(也是很棒的)论文 - 为什么函数式编程很重要。

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

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

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

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

(强调我的)

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

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

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

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

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