"combine" 以功能方式在 javascript 中发挥作用?

To "combine" functions in javascript in a functional way?

我正在学习函数式编程,我想知道是否有办法 "combine" 像这样的函数:

function triple(x) {
    return x * 3;
}
function plusOne(x) {
    return x + 1;
}
function isZero(x) {
    return x === 0;
}
combine(1); //1
combine(triple)(triple)(plusOne)(1); // 10
combine(plusOne)(triple)(isZero)(-1); // true

如果 para 是一个函数,它将 "combines" 函数转化为自身,如果不是,它将 return 最终结果。 谢谢!

您可以简单地在 return 值本身上调用该函数,例如:

plusOne(triple(triple(1))) // 10
isZero(triple(plusOne(-1))) // true

传承

这是一个数学概念,叫做 function composition

       f(x) = y
       g(y) = z

    g(f(x)) = z

   (g•f)(x) = z

最后一行读作 "g of f of x equals z"。组合函数的伟大之处在于消除了。请注意,在 g(f(x)) = z 中,我们采用 x 输入并获得 z 输出。这会跳过中间点 y.

组合是创建 higher-order functions 并保持代码整洁的好方法。很明显我们为什么要在 Javascript 程序中使用它。


补偿

JavaScript 是一种多范式语言,具有丰富的功能支持。我们可以创建一个简单的 comp 函数,它结合了两个输入函数 gf,并生成 new 函数 -

function triple(x) {
  return x * 3
}

function plusOne(x) {
  return x + 1
}

function comp(g, f) {
  return function(x) {
    return g(f(x))        // "g of f of x"
  }
}

const myfunc =
  comp(triple, plusOne)

console.log(myfunc(1))

评价

triple(plusOne(1))
triple(2)
6

撰写

正如问题所暗示的,我们很可能想要组合两个以上的函数。下面我们编写 compose,它采用 all 的输入函数,并使用上面的简单 comp 对它们进行 reduce。如果没有给出函数,我们 return 空函数,identity -

const triple = (x) =>
  x * 3

const plusOne = (x) =>
  x + 1

const comp = (g, f) =>
  x => g(f(x))                     // "g of f of x"

const identity = (x) =>
  x

const compose = (...all) =>
  all.reduce(comp, identity)

const myfunc =
  compose(triple, triple, plusOne) // any amount of funcs

console.log(myfunc(1))

评价

triple(triple(plusOne(1)))
triple(triple(2))
triple(6)
18

管道

你可以随心所欲地发挥创意。下面,我们写 pipe 允许我们的程序以舒适的从左到右的方向阅读 -

const triple = (x) =>
  x * 3

const plusOne = (x) =>
  x + 1

const pipe = x =>
  f => pipe(f(x))

pipe(1)(plusOne)(triple)(triple)(console.log)           // 18
pipe(3)(triple)(plusOne)(triple)(plusOne)(console.log)  // 31

表达式一的计算 -

f => pipe(f(1))
pipe(plusOne(1))
f => pipe(f(2))
pipe(triple(2))
f => pipe(f(6))
pipe(triple(6))
f => pipe(f(18))
pipe(console.log(18))
18

和表达式二-

f => pipe(f(3))
pipe(triple(3))
f => pipe(f(9))
pipe(plusOne(9))
f => pipe(f(10))
pipe(triple(10))
f => pipe(f(30))
pipe(plusOne(31))
f => pipe(f(31))
pipe(console.log(31))
31

相关技巧

柯里化函数部分应用是与函数组合融为一体的概念。上面的pipeanother Q&A中介绍为$,这里再次演示-

const $ = x =>           // "pipe", or whatever name you pick
  k => $ (k (x))
  
const add = x => y =>    // curried add
  x + y

const mult = x => y =>   // curried mult
  x * y
  
$ (1)                    // 1
  (add (2))              // + 2 = 3
  (mult (6))             // * 6 = 18
  (console.log)          // 18
  
$ (7)                    // 7
  (add (1))              // + 1 = 8
  (mult (8))             // * 8 = 64
  (mult (2))             // * 2 = 128
  (mult (2))             // * 2 = 256
  (console.log)          // 256

function triple(x) {
    return x * 3;
}
function plusOne(x) {
    return x + 1;
}
function isZero(x) {
    return x === 0;
}

var combine = function (v) {
    var fn = [];
    function _f(v) {
        if (typeof v === 'function') {
            fn.push(v);
            return _f;
        } else {
            return fn.reduce(function (x, f) { return f(x); }, v);
        }
    }
    return _f(v);
};

var a, b;
console.log(combine(1)); //1
console.log(combine(triple)(triple)(plusOne)(1)); // 10
console.log(combine(plusOne)(triple)(isZero)(-1)); // true
console.log(a = combine(plusOne)); // function ...
console.log(b = a(triple)); // function ...
console.log(b(5)); // 18
console.log(combine(triple)(plusOne)(triple)(plusOne)(triple)(plusOne)(1)); // 40
// @naomik's examples
var f = combine(triple); 
var g = combine(triple)(triple); 
console.log(f(1)); // 3
console.log(g(1)); // 9 (not 6 as you stated)

在JavaScript.In某种意义上,也可以通过组合简单函数来构建复杂的功能,组合是函数的嵌套,将一个函数的结果作为输入传递给下一个函数。但是我们不会创建难以理解的嵌套量,而是创建一个高阶函数 compose(),它采用我们想要组合的所有函数,并且 returns 我们将在我们的应用程序中使用一个新函数.

function triple(x) {
  return x * 3;
}
function plusOne(x) {
  return x + 1;
}
function isZero(x) {
  return x === 0;
}

const compose = (...fns) => x =>
  fns.reduce((acc, cur) => {
    return cur(acc);
  }, x);

const withCompose = compose(triple, triple, isZero);
console.log(withCompose(1));

功能组合已经在其他答案中详细说明,主要是 ,所以我的 2 美分直接用于回答您的最新问题:

If the para is a function, it "combines" the function into itself, and if not it will return the final result. Thanks!

const chain = (g, f = x => x) => 
  typeof g === 'function'
  ? (y) => chain(y, (x) => g(f(x)))
  : f(g);

// ====

const triple = x => x * 3;
const inc = x => x + 1;
const isZero = x => x === 0;

console.log(
  chain(inc)(triple)(isZero)(-1),
);