函数组合 - 多次循环数组进行多个操作不是效率低下吗?

ptm*_*der 3 javascript functional-programming function node.js ecmascript-6

我试图理解函数式编程的概念和基础知识。我不会死守 Haskell、Clojure 或 Scala。相反,我使用 JavaScript。

因此,如果我理解正确的话,函数式编程背后的想法是使用纯函数编写软件应用程序 - 它负责处理应用程序中的单一职责/功能,而不会产生任何副作用。

组合以这样一种方式进行:一个函数的输出通过管道作为另一个函数的输入(根据逻辑)。

我编写了两个分别用于加倍和递增的函数,它们以整数作为参数。接下来是一个实用函数,它组成了作为参数传入的函数。

{
    // doubles the input
    const double = x => x * 2

    // increments the input
    const increment = x => x + 1

    // composes the functions
    const compose = (...fns) => x => fns.reduceRight((x, f) => f(x), x)

    // input of interest
    const arr = [2,3,4,5,6]

    // composed function
    const doubleAndIncrement = compose(increment, double)

    // only doubled
    console.log(arr.map(double))

    // only incremented
    console.log(arr.map(increment))

    // double and increment
    console.log(arr.map(doubleAndIncrement))
}
Run Code Online (Sandbox Code Playgroud)

输出如下:

[4, 6, 8, 10, 12]  // double
[3, 4, 5, 6, 7]    // increment
[5, 7, 9, 11, 13]  // double and increment
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是,在这种情况下,reduceRight 函数将遍历数组两次来应用这两个函数。

如果数组变得更大,这不是效率低下吗?

使用循环,可以在一次遍历中完成同一循环中的两个操作。

如何防止这种情况发生,或者我的理解是否有任何错误?

Ala*_*air 5

它会map遍历数组,并且只发生一次。reduceRight正在遍历组合函数列表(在示例中为 2),并通过该函数链将数组的当前值线程化。您描述的等效低效版本是:

const map = f => x => x.map(f)
const doubleAndIncrement = compose(map(increment), map(double))

// double and increment inefficient
console.log(doubleAndIncrement(arr))
Run Code Online (Sandbox Code Playgroud)

这揭示了地图必须满足的定律之一

map(compose(g, f))等价于(同构)compose(map(g), map(f))

但正如我们现在所知,后者可以通过将其简化为前者而变得更加高效,并且它只会遍历输入数组一次。

  • 仅当您坚持使用“map”(即保留结构)时,这才有效。如果您还想过滤或只获取第一个/最后一个元素怎么办?那么你需要传感器。 (2认同)