Last active
February 1, 2018 05:16
-
-
Save superhawk610/dcd5bbca786e05f6533896267bc9f058 to your computer and use it in GitHub Desktop.
Wrap your head around functional programming!
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
/** | |
* Functional Programming!!! | |
*/ | |
const val = 5, | |
/** | |
* The identity function takes a function and returns a copy of that function. | |
* The use of the spread (...) operator here is key to understanding more | |
* complex functional programming, like curry() below. | |
*/ | |
identity = f => (...args) => f(...args), | |
/** | |
* Here are three of the key functions to understand for functional programming. | |
* | |
* curry() takes a non-unary function that accepts multiple functors and returns | |
* a function that accepts exactly one functor | |
* | |
* pipe() accepts a set of transform functions and returns a function that applies | |
* each of these transforms, one at a time, to the given functor | |
* | |
* compose() works just like pipe(), just in reverse. For example, given the composed | |
* function f(g(h(x))), you can rewrite it as a pipe: | |
* | |
* pipe(h, g, f) | |
* | |
* or as a composition: | |
* | |
* compose(f, g, h) | |
* | |
* Notice that compose follows the same order as if you were writing out the complete | |
* chain, while pipe requires the transforms to be in the order you would like to | |
* apply them, much like gates filter material flowing through a pipe. | |
*/ | |
curry = (f, arr = []) => (...args) => | |
(a => (a.length === f.length ? f(...a) : curry(f, a)))([...arr, ...args]), | |
pipe = (...funcs) => x => funcs.reduce((v, f) => f(v), x), | |
compose = (...funcs) => x => funcs.reduceRight((v, f) => f(v), x), | |
/** | |
* Here are some basic unary transformation functions - they take | |
* a single functor (input) and transform & return it | |
*/ | |
double = x => x * 2, | |
square = x => x * x, | |
half = x => x / 2, | |
/** | |
* This transformation function is configurable via a parameter, | |
* so instead of just passing it directly you'll actually want to call | |
* it with a value and pass the function it returns - now you're thinking | |
* functionally! | |
*/ | |
add = x => y => x + y, | |
/** | |
* Here's a basic non-unary function - it doesn't fit too well in a pipe/ | |
* compose function, so we'll curry it to split it up into a chain of unary | |
* functions! | |
* | |
* curryedSum can be called in a few different ways: | |
* | |
* curryedSum(1, 2, 3) // 6 | |
* curryedSum(1, 2)(3) // 6 | |
* curryedSum(1)(2, 3) // 6 | |
* curryedSum(1)(2)(3) // 6 | |
* | |
* You can also partially compose it, as such: | |
* | |
* let foo = curryedSum(1, 2) // x => 1 + 2 + x | |
* let bar = curryedSum(1) // x => 1 + x + y | |
* and then use it in a pipe: | |
* | |
* pipe(foo) | |
* pipe(bar(2)) | |
*/ | |
sum = (x, y, z) => x + y + z, | |
curryedSum = curry(sum), | |
/** | |
* Here's a basic unary trace function - it simply logs the current value | |
* it is passed with a tag. | |
*/ | |
trace = tag => x => { | |
console.log(` [${tag}] => ${x}`) | |
return x | |
}, | |
/** | |
* The following transform functions will all have the same result! | |
*/ | |
transform = x => double(square(add(2)(x))), | |
composedTransform = compose(double, square, add(2)), | |
pipedTransform = pipe(add(2), square, double), | |
pipedTracedTransform = pipe( | |
trace('initial'), | |
add(2), | |
trace('add(2)'), | |
square, | |
trace('square'), | |
double, | |
trace('double') | |
) | |
console.log() | |
console.log(`Transform takes a number (${val}) and performs the following`) | |
console.log('operations:') | |
console.log(' - adds 2') | |
console.log(' - squares the value') | |
console.log(' - doubles the value') | |
console.log() | |
console.log(' transform: ' + transform(val)) | |
console.log('composedTransform: ' + composedTransform(val)) | |
console.log(' pipedTransform: ' + pipedTransform(val)) | |
console.log() | |
console.log('By simply adding a trace() call to the pipe, we can watch the') | |
console.log('transformation at each step, like so:') | |
console.log() | |
console.log('\n returned value: ' + pipedTracedTransform(val)) | |
console.log() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment