如何在另一个FP中组合功能?

Rad*_*dex 2 javascript functional-programming ecmascript-6

我正在学习JavaScript中的函数编程,目前我有以下代码.

我想将这两个函数组合在另一个函数中,该函数使用户通过一个值并使结果等于传递的值加上10乘以3使用以下函数.

伪代码示例:

 const myFormulat= add(10).multiply(3);
Run Code Online (Sandbox Code Playgroud)

如何仅使用vanilla JS ES6编写此功能?

function add(x){
  return function(y){
    return y + x;
  };
}

function multiply(x){
  return function(y){
    return y * x;
  };
}

// my calculation
// get x add 10 and after multiply by 3
Run Code Online (Sandbox Code Playgroud)

Tha*_*you 5

熊陷阱和地雷

这个答案仅仅是为了证明为什么这不是一个好主意 - 复杂性通过屋顶基本没有收获.注意我们必须告诉我们的函数何时结束,所以我添加了一个特殊的函数,call所以我们的表达式将如下所示

.add(3).mult(4).call(x)
// where x is the input for the entire function chain
Run Code Online (Sandbox Code Playgroud)

最后一个变化是我们的函数库add,mult等必须被包裹在一些范围限制我们代理的范围.该范围告诉我们我们希望链接的功能的确切位置.

哦,如果这部分的标题不够警告,我们也使用了Proxy.

// helpers
const identity = x => x
const comp = f => g => x => f(g(x))

// magic wand
const using = scope => {
  let acc = identity
  let p = new Proxy({
    call: x => acc(x),
  }, {
    get: (target, name) => {
      if (name in target)
        return target[name]
      else if (name in scope)
        return x => {
          acc = comp (scope[name](x)) (acc)
          return p
        }
      else
        throw Error(`${f} is not undefined in ${scope}`)
    }
  })
  return p
}

// your functions wrapped in a scope
const math = {
  add: x => y => x + y,
  mult: x => y => x * y
}

// chain it up
const main = using(math).add(3).mult(4).add(5).mult(6).call

console.log(main(2))
// (((2 + 3) * 4) + 5) * 6
// ((5 * 4) + 5) * 6
// (20 + 5) * 6
// 25 * 6
// 150
Run Code Online (Sandbox Code Playgroud)


功能构成

但严重的是,不要这样做..考虑到您的起点,通过操作员推送所有内容是不自然的,您应该寻找更有效的方法来组合功能.

我们可以使用稍微不同的表示法有效地做同样的事情 - 这里最大的区别是复杂度几乎为零

const compose = (f,...fs) => x =>
  f === undefined ? x : compose (...fs) (f(x))
  
const add = x => y => x + y

const mult = x => y => x * y

const main = compose (add(3), mult(4), add(5), mult(6))

console.log(main(2)) // => 150
Run Code Online (Sandbox Code Playgroud)


函子

也许你不喜欢传统的功能组合,这很好,因为我们还有另一种方法来解决使用Functors的问题- 简单地说,Functor是一个带有map函数的容器.

下面我们有一个Box函数,它将值放在我们的容器中.该map函数接受一个函数,并使用用户指定函数的返回值创建一个新Box.最后,我们有一个fold功能,让我们可以开箱即用

同样,它改变了我们编写代码的方式,但减少的复杂性是巨大的(与Proxy示例相比)

const Box = x => ({
  map: f => Box(f(x)),
  fold: f => f(x)
})

const add = x => y => x + y

const mult = x => y => x * y

const main = Box(2).map(add(3)).map(mult(4)).map(add(5)).map(mult(6)).fold

main(console.log) // 150
Run Code Online (Sandbox Code Playgroud)