当您实际上想产生副作用时,“函数式编程”背后的原理是什么?

Plí*_*lpa 5 javascript functional-programming

我知道纯函数在“函数编程”范例中,您创建了一个没有任何副作用的函数,并且对于输入,它总是返回相同的输出,例如:

function (a,b) {
    return a + b;
}
Run Code Online (Sandbox Code Playgroud)

这是一个纯函数,因为对于输入,我总是返回相同的输出,并且没有产生任何副作用。好吧,我明白了。

但是,当我实际上想要创建副作用(例如更改DOM中的文本内容)时,如何制作“纯函数”,如何保留在“函数编程”范例中:

function changeContent () {
   let content = document.querySelector("#content");
   content.textContent = 'Hello World';
}
Run Code Online (Sandbox Code Playgroud)

这个函数有一个副作用,它没有获得输入,返回输出,而是产生了副作用,但这实际上是函数的重点。这仍然是“函数式编程”吗?在这种情况下,如何留在“函数式编程”范式中?

Ber*_*rgi 4

当我实际上想创建副作用时,如何才能保持“函数式编程”范式?

你真的不能。纯函数不能有任何副作用。

当然,这意味着我们实际上无法将执行任何操作的程序建模为纯函数。有两种方法可以解决这个问题:

  • 牺牲纯度。只需编写一个有副作用的函数即可。彻底记录下来,以便每个使用该函数的人都知道这一点。对程序的命令部分进行不同的推理。

    这是大多数编程语言中的首选解决方案,因为它们不强制纯粹性,而且您通常可以侥幸逃脱。

  • 构建一个(纯)数据结构,明确描述您希望程序具有的效果。然后有一个不纯的“解释器”来执​​行它们来“运行”你的程序。(我不会在这里详细介绍这种数据结构如何工作,有不同的方法,并且解释将超出问题的范围)。

    在强制所有函数的纯度的 Haskell 中,这种数据结构是IO基本上描述命令式计算的类型,并且它的解释器内置于运行时中。
    Elm 也保证了纯度,Elm 架构可以在浏览器中对 Web API 和 DOM 进行建模,并且每个程序在编译为 JS 时都需要较小的运行时。

在 JavaScript 中,没有这样的解释器。您可以自己构建一个(或使用为此目的构建的库),但最终您必须run在程序中的某个位置调用它的函数,这会将您带回#1。

特别是对于 DOM:描述文档中的更改的数据结构将相对容易构建。您甚至可以引入纯粹的功能优化,例如,避免多次写入同一位置或随后将被删除的位置。

然而,DOM 是 JavaScript 异步特性的基本组成部分。描述与事件输入和输出的潜在并发交互是很困难的。