functional javascript w/ composition

node v6.17.1
version: 6.0.1
endpointsharetweet
One of the most important ideas in software development is: keep it simple. The problem is, every developer believes all code they write is simple & beautiful. Without getting into the tar pit of defining "Simple Code" - I'll show one method which has worked well for me. Goal: write focused, pluggable & testable functions by following 2 rules: 1. Restrict functions to single-purpose. AND 2. Restrict functions to only 1 argument (or 2 for (err, value) style). This can be an array or object with many dimensions. Let's write some example "Higher Order Functions" to do multiple math steps/functions. Pure ES2016 - no "frameworks" - just a tape test.
/* @author: Dan Levy <Dan@DanLevy.net> Twittering: @justsml */ const test = require('tape') // The '_composer' wrapper fn supports reversing execution order, literally only changes the inner fn '_partial' const compose = _composer() // note: '_composer' defined at the end, read tests first const composeRight = _composer(true) // Define a Pure-at-heart function (https://en.wikipedia.org/wiki/Pure_function) const add5 = n => { n = 5 + parseInt(n, null) return n // required } test('sequence of 3 functions', t => { const add15 = compose(add5, add5, add5) t.equals(add15(0), 15) t.equals(add15(5), 20) t.equals(add15(10), 20) t.end() }) // Define some Pure-at-heart functions (https://en.wikipedia.org/wiki/Pure_function) const half = n => { n = n * 0.5 return n // required } const square = n => { n = n * n return n // required } test('sequence of different functions', t => { const add5HalfSquare = compose(add5, half, square) t.equals(add5HalfSquare(5), 25, 'I can caz maths?') // 5+5==10, half(10)==5, 5*5==25 t.end() }) // Forward/reverse function chain helper - See examples, way simpler in code - tldr: this glues other functions toghether function _composer(reverse = false) { // @uglytruth // Returns higher-order-function, executes using Array.reduce syntax (link mdn article). // Starting with the initial arguments, each function is sequentially executed, passing arguments from one function to the next - functions MUST RETURN THE VALUE TO HAND-OFF. // Only supports single param functions - **this is a feature** return function _directionalFunChain() { const fns = Array.from(arguments); return function _partial() { return Array.from(fns) [reverse ? 'reduceRight' : 'reduce']((last, fn) => fn && fn(last) || last, [...arguments]); }.bind(this); } }
Loading…

2 comments

  • posted 7 years ago by brianleroux
    <3 it!
  • posted 7 years ago by thevige
    fantastic

sign in to comment