javascriptfunctional-programmingchainingfunction-composition

Chaining and Function Composition


Here is a piece of code I am trying to understand:

const seq2 = (f1, f2) => {
 return (...args) => {

  return f2( f1( ...args) );
 }
}



const seq = ( f1, ...fRest) =>
 fRest.reduce( seq2, f1 );

const elevator = {
 floor: 5
};

const up = elevator => {
 return {
  floor: elevator.floor + 1
 }
};

const down = elevator => {
 return {
  floor: elevator.floor - 1
 }
};


const move = seq( up, up, down, up);
const newElevator = move( elevator );



console.log( newElevator.floor ) // shows 7

this is an example from js functional programming course. And I am trying to figure out if I could simplify seq function so it would look like this

const seq = ( ...fRest) => fRest.reduce( seq2 );

????

Is there any specific reason why I have to pass f1 as a first argument and then pass it further to the reduce method as an initialValue ?? When I won't specify the initialValue in the reduce method wouldn't it treat the first array element - accumulator - as an initialValue by default? I will much appreciate if someone could explain to me what is going on in that code :)


Solution

  • seq() would attempt to reduce an empty array without an accumulator, which is an error – not that f1 fixes this the way the author has it written here.

    initialValue – Value to use as the first argument to the first call of the callback. If no initial value is supplied, the first element in the array will be used. Calling reduce() on an empty array without an initial value is an error – source MDN: Array.prototype.reduce

    A more robust implementation of seq will not cause an error when seq() is used to build an empty sequence

    const identity = x =>
      x
    
    const seq2 = (f, g) =>
      (...args) => f (g (...args))
    
    const seq = (...fs) =>
      fs.reduce (seq2, identity)
    
    const up = elevator =>
      ({ floor: elevator.floor + 1 })
      
    const down = elevator =>
      ({ floor: elevator.floor - 1 })
    
    console.log
     ( seq (up, up, down, up) ({ floor: 3 }) // { floor: 5 }
     , seq () ({ floor: 3 })                 // { floor: 3 }
     )

    A simplified version of seq that promotes better functional hygiene by disallowing composition of variadic functions

    const identity = x =>
      x
    
    const seq = (f = identity, ...rest) =>
      f === identity
        ? f
        : x => seq (...rest) (f (x))
    
    const up = elevator =>
      ({ floor: elevator.floor + 1 })
      
    const down = elevator =>
      ({ floor: elevator.floor - 1 })
    
    console.log
     ( seq (up, up, down, up) ({ floor: 3 }) // { floor: 5 }
     , seq () ({ floor: 3 })                 // { floor: 3 }
     )