Created
August 15, 2018 06:55
-
-
Save AndrewThian/0bb3268c7e353391d2c98d5871207bda to your computer and use it in GitHub Desktop.
A simple gist to explain using HoF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Simple logging functionality | |
const sqrt = Math.sqrt; | |
console.log("result", sqrt(16)) | |
console.log("result", sqrt(9)) | |
// ======= logging ====== // | |
// Introducing logging within the function | |
// we want to log the incoming parameters in the function | |
const sqrt = int => { | |
console.log(int) | |
return Math.sqrt(int) | |
} | |
console.log("result", sqrt(16)) | |
console.log("result", sqrt(9)) | |
// ======= higher order function logging ====== // | |
// We can do better than log within the sqrt function | |
// Higher order logger to allow us to pass in | |
// any function and it will log the parameters | |
const log = fn => (...args) => { | |
// takes in a function as a parameter | |
// returns a function with arguments | |
console.log(...args) | |
return fn(...args) | |
} | |
// we don't have to pollute the Math.sqrt function | |
// log() wraps the Math.sqrt fn and returns a new fn with logging capabilities | |
// that we can assign to function variable to use | |
const sqrt = log(Math.sqrt) | |
console.log("result", sqrt(16)) | |
console.log("result", sqrt(9)) | |
// ======= higher order caching ====== // | |
// lets take it a step further to include caching into our logging HoF | |
const log = fn => (...args) => { | |
// takes in a function as a parameter | |
// returns a function with arguments | |
console.log(...args) | |
return fn(...args) | |
} | |
// we have a memoize fn that takes in a fn and returns another fn | |
// where we initialize a little store.. | |
const memoize = fn => { | |
const results = {} | |
return (...args) => { | |
const key = JSON.stringify(args) | |
// if our results store already has a key | |
// we should return that key's value | |
// otherwise, set the key's value to the executed function | |
return results.hasOwnProperty(key) ? results[key] : (results[key] = fn(...args)) | |
} | |
} | |
// now our sqrt function has 2 additional capabilities.. | |
// caching and logging functionality. | |
const sqrt = memoize(log(Math.sqrt)) | |
console.log("result", sqrt(16)) | |
// 16 | |
// result 4 | |
console.log("result", sqrt(9)) | |
// 9 | |
// result 3 | |
// now if we run sqrt(16) again | |
console.log("result", sqrt(16)) | |
// result 4 | |
// we do not log the function execution again | |
// because our memoize decorator already cached | |
// the value of sqrt(16) | |
// now we have two higher order function(decorators) | |
// ======= composing functions ====== // | |
// using nested decorators is a bit messy | |
// we can create an abstraction to avoid nesting | |
// compose -> well known abstraction | |
const compose = (...fns) => arg => { | |
// it takes an array of functions | |
// returns a function that takes in an argument | |
// we use reduceRight array method: | |
// MDN -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight | |
// takes two parameters (result, fn) | |
// passing the argument recursively into each accumulator function | |
return fns.reduceRight((result, fn) => fn(result), arg) | |
} | |
// seems more ergonomic | |
// however, this doesn't work if we have multiple parameters in our child function | |
const sqrt = compose(memoize, log)(Math.sqrt) | |
// ===== multiple arguments ===== // | |
// I know this seems a bit crazy | |
const compose = (...fns) => (...args) => { | |
return fns.reduceRight((result, fn) => [fn(...result)], args)[0] | |
} | |
// lemme break it down | |
const compose = (...fns) => (...args) => { | |
// reduceRight accumulates an array from the right | |
// i.e accumulate from the last index in the array | |
// rather than the first | |
const _fns = fns.reduceRight((result, fn) => { | |
// result is the accumulator | |
// result here is equivalent to args on line 122 | |
console.log("result: ", ...result) | |
// fn here is the function variable log || memoize | |
console.log("fn: ", fn) | |
console.log("pass in arguments via spread operator into fn") | |
// passing the accumulator into each composing function | |
// will return a function that gets added to the next iteration | |
let func = fn(...result) | |
console.log("func: ", func) | |
return [func] | |
}, args) | |
console.log("compose: ", _fns) | |
// finally we return the composed function to the variable | |
return _fns[0] | |
} | |
// ===== Reference ===== // | |
// typescript and decorators: https://www.youtube.com/watch?v=lepKIVH3ZfE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment