【问题标题】:What is the philosophy behind "functional programming" when you actually want to create a side effect?当您真正想要创建副作用时,“函数式编程”背后的哲学是什么?
【发布时间】:2018-05-28 14:37:44
【问题描述】:

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

function (a,b) {
    return a + b;
}

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

但是我如何才能制作“纯函数”,当我真正想要创建副作用时,我如何才能停留在“函数式编程”范式中,例如更改 DOM 中的文本内容,例如:

function changeContent () {
   let content = document.querySelector("#content");
   content.textContent = 'Hello World';
}

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

【问题讨论】:

  • 在 100% 纯严格的函数式编程中,例如Haskell,副作用被表示为特殊类型并引入了所有新的范例。这根本不能很好地转化为 Javascript。 Javascript 是一种多范式 语言,它不是 100% 纯函数式编程......
  • @deceze 你不必纯粹为了使用代数数据类型或仿函数等。一切都与 Javascript 中的策略有关。
  • 这个 q 太宽泛了。这是一个广泛的答案:用类型编码你的副作用并定义,对于这种行为,这种类型等同于其他类型。此外,您还需要一些特定的组合器,仅此而已。
  • Ch 8 - Tupperware of Mostly Adequate Guide to Functional Programming 谈到了这个

标签: javascript functional-programming


【解决方案1】:

当我真正想要创建副作用时,如何才能停留在“函数式编程”范式中?

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

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

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

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

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

    在强制执行所有函数的纯度的 Haskell 中,此数据结构是 IO 类型,它基本上描述了命令式计算,并且它的解释器内置在运行时中。
    在同样保证纯度的 Elm 中,有 Elm architecture 来模拟在浏览器中使用 Web API 和 DOM,并且在编译为 JS 时,每个程序都需要一个小的运行时。

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

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

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

【讨论】:

    【解决方案2】:

    我不确定它是否有用,但您可以将 DOM 内容传递给该函数并获得一个新的结果。像这样:

    function changeContent(content, value) {
        let result = deepcopy(content);       //copy the passed object to preserve it from modifying
        result.textContent = value; //change smth in copied object
        return result;
    }
    

    deepcopy 是一个返回对象副本的函数(如果你直接设置result = content,那么更改result 对象中的某些值也会导致更改content 对象中的值)。 注意:deepcopy 不是内置函数,您应该自己编写或使用库。

    P.S.如果这个答案没有帮助,你可以阅读一篇关于函数式编程的文章here

    【讨论】:

    • 返回修改后的对象后,您可以将其设置为 DOM 内容,但如果这是您想要的,最好在函数内修改内容(更快更容易)。
    • 虽然你可以做你所描述的事情,但这毫无意义,因为你仍然需要修改 DOM,你只是推迟了不可避免的事情,而且你让事情变得更糟,因为现在你有相同的副作用,但是您需要删除 DOM 元素并将其替换为新元素,如果该元素附加了事件侦听器,这将更加困难、昂贵甚至有时甚至是危险的,然后只需就地修改元素即可。
    猜你喜欢
    • 2016-08-15
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    相关资源
    最近更新 更多