- partial
- partial
- partialR
- curry
- curryR
- compose
- flow
- asyncFlow
- apply
- unapply
- flip
- over
- reduce
- reduceR
- map
- filter
- find
- reverse
- uniq
- flat
- chunk
- zip
- union
- difference
- intersection
- defer
- partition
- takeWhile
- takeWhileR
- unfold
- y
- memoize
one-liner functional utilities in JavaScript
Meta
- author: Stefan Maric <[email protected]>
- license: Copyright © 2017 Stefan Maric <[email protected]> This work is free. You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
Partially applies f
to arguments args
, that's it, returns a function that
invokes f
with args
prepended to the arguments it receives.
f
Function Function to be partially applied.args
any Arguments to partially apply.
const sum = (a, b) => a + b
const sumTen = partial(sum, 10)
sumTen(5)
// => 15
Returns Function Partially applied function.
Similar to partial, but arguments applied from right to left: Partially
applies f
to arguments args
, that's it, returns a function that invokes
f
with args
appended to the arguments it receives.
f
Function Function to be partially applied.args
any Arguments to partially apply.
const pretty = partialR(JSON.stringify, null, 2)
pretty({ name: 'John', age: 28, children: [{ name: 'Carlos', age: 8 }] })
// => "{
// "name": "John",
// "age": 28,
// "children": [
// {
// "name": "Carlos",
// "age": 8
// }
// ]
// }"
Returns Function Partially applied function.
Automagical currying. Creates a function that invokes f
if all expected
arguments are passed, or returns a function that expects the rest of the
arguments.
Strict curry alternative:
f => x => f.length > 1 ? curry(f.bind(null, x)) : f(x)
f
Function Function to be curried.
const foo = (a, b, c) => [a, b, c]
foo(1, 2, 3)
// => [1, 2, 3]
const curriedFoo = curry(foo)
curriedFoo(1)
// => Function
curriedFoo(1)(2)(3)
// => [1, 2, 3]
curriedFoo(1)(2, 3)
// => [1, 2, 3]
curriedFoo(1, 2)(3)
// => [1, 2, 3]
curriedFoo(1)()(2)()(3)
// => [1, 2, 3]
curriedFoo(1)(undefined)(3)
// => [1, undefined, 3]
Returns Function Curried function.
Just like curry, but arguments are partially applied from right to left.
Strict curryR alternative:
(f, ari = f.length) => x => ari <= 1 ? f(x) : curryR((...args) => f(...args, x), ari - 1)
Alternative using partialR:
(f, ari = f.length) => (...args) => args.length >= ari ? f(...args) : curryR(partialR(f, ...args), ari - args.length)
const bar = (a, b, c) => [a, b, c]
bar(1, 2, 3)
// => [1, 2, 3]
const curriedBar = curryR(bar)
curriedBar(1)
// => Function
curriedBar(1)(2)(3)
// => [3, 2, 1]
curriedBar(1)(2, 3)
// => [2, 3, 1]
curriedBar(1, 2)(3)
// => [3, 1, 2]
curriedBar(1)()(2)()(3)
// => [3, 2, 1]
curriedBar(1)(undefined)(3)
// => [3, undefined, 1]
Returns Function Curried function.
Compose functions from right to left — creates a function than, when invoked, calls the last function in the array with its arguments, the result of it is passed as argument to the previous function and so on until the value is returned.
Simpler alternative: fns => x => fns.reduceRight((v, f) => f(v), x)
const reverse = s => s.split('').reverse().join('')
const lowercase = s => s.toLowerCase()
const capitalize = s => s.replace(/\b\w/g, c => c.toUpperCase())
const bang = s => s + '!'
const anadrome = compose([
bang,
capitalize,
lowercase,
reverse
])
anadrome('Redraw Dog Flow')
// => "Wolf God Warder!"
Returns Function Composition of the functions.
Compose functions from left to right — creates a function that, when invoked, calls the first function in the array with its arguments, the result of it is passed as argument to the next function and so on until the value is returned.
Simpler alternative: fns => x => fns.reduce((v, f) => f(v), x)
const reverse = s => s.split('').reverse().join('')
const lowercase = s => s.toLowerCase()
const capitalize = s => s.replace(/\b\w/g, c => c.toUpperCase())
const bang = s => s + '!'
const anadrome = flow([
reverse,
lowercase,
capitalize,
bang
])
anadrome('Redraw Dog Flow')
// => "Wolf God Warder!"
Returns Function Composition of the functions.
Compose async and sync operations seamless.
const wait = (ms, x) => new Promise(resolve => setTimeout(() => resolve(x), ms))
const doStuff = asyncFlow([
async n => (n + await wait(1000, 4)) * await wait(2000, 6),
n => n % 10,
async n => n / await wait(1000, 2)
])
doStuff(Promise.resolve(7))
.then(console.log)
.catch(console.error)
// => 3
Returns Function Composition of the functions.
Creates a function that takes an array of arguments args
and inkokes f
passing each item of args
as function arguments, similar to Function#apply.
This allows to convert a variadic or n-ary function into an unary function.
f
Function Variadic/n-ary function to apply.
Math.max(1, 2, 3)
// => 3
apply(Math.max)([1,2,3])
// => 3
Returns Function Converted unary function.
The opposite of apply
— creates a function that takes any number of
arguments and invokes f
passing them as an array.
f
Function Unary function to unapply.
Array.from([1, 2, 3])
// => [1, 2, 3]
unapply(Array.from)(1, 2, 3)
// => [1, 2, 3]
Returns Function Converted variadic function.
Creates a function with inverted argument order.
f
Function Function to flip.
const join = (...args) => args.join(',')
join(1, 2, 3)
// => '1,2,3'
flip(join)(1, 2, 3)
// => '3,2,1'
Returns Function Flipped function.
Creates a function that maps over fns
functions passing all its arguments.
const range = over([Math.min, Math.max])
range(1,2,3,4,5)
// => [1,5]
Returns Function Function that maps over fns
.
A more functional reduce implementation.
Simpler alternative: (f, acc, xs) => xs.reduce(f, acc)
const sum = curry(reduce)((acc, el) => acc + el, 0)
sum([1, 2, 3])
// => 6
Returns any Reduced value.
A more functional reduceRight implementation.
NOTE: this implementation is similar to Ramda's, which iterator is called
with the (value, acc)
signature while Array#reduceRight
and
lodash.reduceRight
keep the order from reduce
as (acc, value)
.
Simpler alternative: (f, acc, xs) => xs.reduceRight(f, acc)
const flatten = curry(reduceR)((el, acc) => acc.concat(el), [])
flatten([[0, 1], [2, 3], [4, 5]])
// => [4, 5, 2, 3, 0, 1]
Returns any Reduced value.
A more functional Array#map implementation.
Simpler alternative: (f, xs) => xs.map(f)
Alternative in terms of reduce:
(f, xs) => reduce((acc, el) => [...acc, f(el)], [], xs)
const double = n => n * 2
map(double, [1, 2, 3])
// => [2, 4, 6]
Returns Array New array with mapped values.
A more functional Array#filter implementation in terms of reduce
.
Simpler alternative: (f, xs) => xs.filter(f)
const isEven = n => n % 2 === 0
filter(isEven, [1, 2, 3, 4, 5])
// => [2, 4]
Returns Array Filtered array.
A more functional Array#find implementation.
Simpler alternative: (f, xs) => xs.find(f)
const isOdd = n => n % 2 !== 0
find(isOdd, [1,3,5,7,9,10,11])
// => 10
Returns any First element that matches f
criteria.
A recursive, more functional, inmmutable implementation of Array#reverse.
Simpler alternative: xs => xs.slice().reverse()
xs
Array Array to reverse.xs.0
xs.xs
...any
reverse([1, 2, 3])
// => [3, 2, 1]
Returns Array Reversed array.
Filters out duplicated items from the array.
xs
Array Array to consider.
uniq([1, 2, 3, 4, 4, 5, 6, 3, 2, 7, 8, 9])
// => [1, 2, 3, 4, 5, 6, 7, 8, 9]
Returns Array Duplicate-free array.
Deep flatten an array.
xs
Array Array to flatten.
flat([1, [2, [3, [4]], 5]])
// => [1, 2, 3, 4, 5]
Returns Array Flat array.
Splits an array in chunks of size n
.
chunk(3, [1, 2, 3, 4, 5, 6, 7, 8, 9])
// => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Returns Array<Array> Array with chunks.
Group elements together by their index.
zip([[1, 2, 3], ['a', 'b', 'c']])
// => [[1, 'a'], [2, 'b'], [3, 'c']]
zip([
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
])
// => [
// [ 1, 4, 7 ],
// [ 2, 5, 8 ],
// [ 3, 6, 9 ]
// ]
zip([
[ 1, 4, 7 ],
[ 2, 5, 8 ],
[ 3, 6, 9 ]
])
// => [
// [ 1, 2, 3 ],
// [ 4, 5, 6 ],
// [ 7, 8, 9 ]
// ]
Returns Array<Array> Zipped array.
Creates a new set of values from all given arrays: A ∪ B ∪ C
union([[1, 2, 3], [3, 4, 5], [5, 6, 7]])
// => [1, 2, 3, 4, 5, 6, 7]
Returns Array Union of the sets.
Get the relative complement of b
in a
, that's it, return all elements of
a
not present in b: B ∖ A
difference([1, 2, 3, 4], [2, 3, 7])
// => [1, 4]
Returns Array Array of elements in a not present in b.
Get the intersection of the given sets, that's it, get the elements common to all arrays.
Returns Array Intersection of arrays.
Create an new deferred promise that can be resolved/rejected from outside.
bag
(optional, default{}
)
const unknownResult = () => {
const deferredPromise = defer()
const errorTimeoutId = setTimeout(
() => {
clearTimeout(successTimeoutId)
deferredPromise.reject(new Error('Error!'))
},
Math.round(Math.random() * 1e4)
)
const successTimeoutId = setTimeout(
() => {
clearTimeout(errorTimeoutId)
deferredPromise.resolve('Success!')
},
Math.round(Math.random() * 1e4)
)
return deferredPromise
}
unknownResult()
.then(console.log)
.catch(console.error)
Returns Promise A new Promise with two extra methods: resolve and reject.
Splits a list into two groups based on f
predicate. The first group
contains those items which f
returns true for, the second contains the
rest.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const isEven = n => n % 2 === 0
partition(isEven, numbers)
// => [[2, 4, 6, 8], [1, 3, 5, 7, 9]]
Returns Array<Array> Array containing the two groups.
Takes elements from xs
until f
predicate returns false.
f
Function Predicate function.xs
Array Array to take from.i
Number Where to start at. (optional, default0
)
const numbers = [8, 12, 6, 10, 24, 16, 9, 20, 4, 26]
const isEven = n => n % 2 === 0
takeWhile(isEven, numbers)
// => [8, 12, 6, 10, 24, 16]
Returns Array Subset of xs
.
Just like takeWhile, but from right to left — takes elements from xs
,
starting from the right, until f
predicate returns false.
const numbers = [8, 12, 6, 10, 24, 16, 9, 20, 4, 26]
const isEven = n => n % 2 === 0
takeWhileR(isEven, numbers)
// => [20, 4, 26]
Returns Array Subset of xs
.
Generate a list from a seed value.
f
Function Iterator function.seed
any Seed value.acc
(optional, default[]
)next
(optional, defaultf(seed)
)
const countDown = n => unfold(seed => seed ? [seed, seed - 1] : false, n)
countDown(7)
// => [7, 6, 5, 4, 3, 2, 1]
const countUp = n => unfold(seed => seed <= n ? [seed, seed + 1] : false, 1)
// => [1, 2, 3, 4, 5, 6, 7]
Returns Array Generated list.
The Y combinator. Allows to create recursive procedures without function declarations.
See: https://en.wikipedia.org/wiki/Fixed-point_combinator#Fixed_point_combinators_in_lambda_calculus See: https://hackernoon.com/casual-functional-adventures-in-javascript-f2baec6c38de
f
Function Function that receives itself.
y(fib => (n, curr = 0, next = 1) => n ? fib(n - 1, next, curr + next) : curr)(7)
// => 13
Returns Function Fixed function.
Create a memoized version of f
. Prevents calculation of previously
calculated values.
f
Function Function to memoize.
let count = 0
const factorial = memoize(n => {
count += 1
return n > 1 ? factorial(n - 1) * n : 1)
})
factorial(5) // => 120
count // => 5
factorial(5) // => 120
count // => 5
factorial(4) // => 24
count // => 5
factorial(7) // => 5040
count // => 7
Returns Function Memoized function.