Skip to content

Instantly share code, notes, and snippets.

@iamstarkov
Forked from montogeek/code.js
Last active October 5, 2017 22:30
Show Gist options
  • Save iamstarkov/b1d0d8d7231be4f956da5af82620b096 to your computer and use it in GitHub Desktop.
Save iamstarkov/b1d0d8d7231be4f956da5af82620b096 to your computer and use it in GitHub Desktop.
// some fp boilerplate
const map = fn => xs => xs.map(fn);
const reduce = (fn, init) => xs => xs.reduce(fn, init);
const concat = (a, b) => a.concat(b);
/* or in a library */
const R = require('ramda');
// async helpers
const toPromise = x => Promise.resolve(x);
const promiseAll = xs => Promise.all(xs);
// decent fp
const getUsersData = regionCode => toPromise(regionCode)
.then(getUsersIdList)
.then(map(fetchUserData))
.then(promiseAll);
// fp, point-free way
const getUsersData = R.pipeP(toPromise,
getUsersIdList,
R.map(fetchUserData),
promiseAll
);
// decent fp
const getPostsData = regionCode => toPromise(regionCode)
.then(getUsersData)
.then(map(getPostsIds))
.then(reduce(concat, []))
.then(map(fetchPostData))
.then(promiseAll);
// fp, point-free way
const getPostsData = R.pipeP(toPromise,
getUsersData,
R.map(getPostsIds),
R.reduce(R.concat, []),
R.map(fetchPostData),
promiseAll
)
/**
* Some science behind this refactoring:
* https://github.com/iamstarkov/fp-js-workshop
*/
/**
* all functions in ramda are curried, but its easy to implement "curry" on your own
* See https://iamstarkov.com/fp-js-workshop/02-practical-intro/#/7
* 4 lines wo/ comments:
const curry = fn => (...args) =>
args.length < fn.length
? (...rest) => curry(fn)(...args, ...rest)
: fn(...args)
*/
const curry = fn => // takes function
// returns a function to await for all arguments
(...args) =>
// if not all arguments provided
args.length < fn.length
// return curried function which accumulates other required arguments
? (...rest) => curry(fn)(...args, ...rest)
// if all arguments are provided,
// just invoke function with them
: fn(...args)
/**
* then there is a concept of compose — right-to-left composition: f(g(x)) = compose(f, g)(x),
* its nice from Math POV, but not really human friendly,
* because you would like to compose left to right — same way you read: compose(a, b)(x) = b(a(x))
* See https://iamstarkov.com/fp-js-workshop/02-practical-intro/#/7
* 3 lines wo/ comments:
const pipe = (headFN, ...restFns) => (...args) => restFns.reduce(
(value, fn) => fn(value),
headFN(...args),
);
*/
// takes functions
// separate left most function from rest functions
const pipe = (headFN, ...restFns) =>
// return piped function,
(...args) => // which takes any arguments
// invoke rest functions after each other
restFns.reduce(
// each function takes result of previous one
(value, fn) => fn(value),
// reduce's initial value is a left most function's result
headFN(...args),
);
const compose = (...fns) => pipe(...fns.reverse());
/**
* Async composition, or Promises composition, or Promises pipe, or pipeP
* See https://iamstarkov.com/fp-js-workshop/03-async/#/22
*/
// synchronous composition
// function composition (left to right)
const pipe = (headFN, ...restFns) => (...args) => restFns.reduce(
(value, fn) => fn(value),
headFN(...args),
);
// asynchronous composition
// promises composition (left to right)
const pipeP = (headPromiseFn, ...restPromiseFns) => (...args) => restPromiseFns.reduce(
(promiseValue, promiseFn) => promiseValue.then(promiseFn),
headPromiseFn(...args)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment