Skip to content

Instantly share code, notes, and snippets.

@m3g4p0p
Last active May 5, 2017 07:04
Show Gist options
  • Save m3g4p0p/874e7c5591f1b02b586f62d5e525049f to your computer and use it in GitHub Desktop.
Save m3g4p0p/874e7c5591f1b02b586f62d5e525049f to your computer and use it in GitHub Desktop.
Piping functions with multiple arguments
/**
* In JavaScript, we can only return one value from a function.
*
* This restricts piping to unary functions -- we couldn't pipe, say,
* both the request and the response object, or the error and the data
* argument from one function to the next without wrapping them in
* another object or an array. Yuck.
*
* So we can't return them both, but we could call another function
* with both! Ok, now we just wrapped them in another function instead
* of a plain object. :-P
*/
function use (...fns) {
let i = 0
return function next (...args) {
const fn = fns[i++]
return fn ? fn(...args, next) : args[0]
}
}
// Contrived sample "usage":
const square = use(
(num, next) => !num || isNaN(num)
? next('Please pass a valid number!')
: next(null, num),
(err, num, next) => err ? (next || num)(err) : next(null, num * num),
(err, res) => err ? console.error(err) : console.log(res)
)
square(2)
/**
* However, we could even drive this further by allowing a function
* to recursively call itself:
*/
function use (...fns) {
let i = 0
return function next (...args) {
const fn = fns[i++]
return (function self (...args) {
return fn ? fn(...args, next, self) : args[0]
})(...args)
}
}
// Something more "useful":
const faculty = use(
(val, next) => next(val, val),
(res, curr, next, self) => curr === 1
? next(res)
: self(--curr * res, curr),
res => console.log(res)
)
faculty(4)
// MIT @ m3g4p0p
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment