Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm learning functional programming and I wonder if there is a way to "combine" functions like this:

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

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

like image 649
user3016883 Avatar asked May 12 '15 17:05

user3016883


People also ask

How do you join two functions in JavaScript?

You can't 'merge' functions as you describe them there, but what you can do is have one function be redefined to call both itself and a new function (before or after the original). var xyz = function(){ console. log('xyz'); }; var abc = function(){ console.

What is JavaScript functional programming?

Functional programming is a paradigm of building computer programs using expressions and functions without mutating state and data. By respecting these restrictions, functional programming aims to write code that is clearer to understand and more bug resistant.

What is function composition in JavaScript?

Function composition is an approach where the result of one function is passed on to the next function, which is passed to another until the final function is executed for the final result. Function compositions can be composed of any number of functions.

What are the 3 types of functions in JavaScript?

There are 3 ways of writing a function in JavaScript: Function Declaration. Function Expression. Arrow Function.


1 Answers

heritage

This is a concept from maths called function composition.

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

    g(f(x)) = z

   (g•f)(x) = z

That last line is read "g of f of x equals z". What's great about composed functions is the elimination of points. Notice in g(f(x)) = z we take an x input and get a z output. This skips the intermediate point, y.

Composition is a great way to create higher-order functions and keep your code sparkly clean. It's plain to see why we'd want this in our Javascript programs.


comp

JavaScript is a multi-paradigm language with rich support for functions. We can create a simple comp function, which combines two input functions, g and f, and results in a new function -

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))

Evaluation

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

compose

Just as the question suggests, it's likely we will want to combine more than two functions. Below we write compose which takes all of the input functions and reduces them using our simple comp from above. If no functions are given, we return the empty function, 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))

Evaluation

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

pipe

You can be as creative as you like. Below, we write pipe which allows our programs to read in a comfortable left-to-right direction -

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

Evaluation of expression one -

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

and expression two -

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

related techniques

Curried functions and partial application are concepts that gel with function composition. pipe above is introduced in another Q&A as $ and demonstrated again here -

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
like image 156
Mulan Avatar answered Oct 21 '22 09:10

Mulan