Source

Top Overview Fun Bool List Dict Coll Ops Misc Author

Overview

fpx: functional programming extensions for JavaScript. Source

See the sibling library espo for stateful programming utils.

Similar to lodash, but more lightweight and specialised. Differences:

Install with npm:

npm i --save fpx

All examples imply an import:

const {someFunction} = require('fpx')

On this page, all fpx words are exported into global scope. You can run examples in the browser console.


Fun

Various higher-order functions.


call(fun, ...args)

Similar to Function#call, but doesn’t take an argument for this. Sometimes useful in function composition.

call(add, 1, 2)
// 3

// equivalent:
// add(1, 2)
// call(add, 1, 2)
// add.call(null, 1, 2)

apply(fun, args)

Similar to Function#apply, but doesn’t take an argument for this. Sometimes useful in function composition.

apply(add, [1, 2])
// 3

// equivalent:
// apply(add, [1, 2])
// add.apply(null, [1, 2])

bind(fun, ...args)

Similar to Function#bind, but doesn’t take an argument for this, and doesn’t affect the this binding of the created function.

Returns a new function that represents partial application of the given function, a common tool in functional programming. When called, it joins arguments from both calls and invokes the original function. Think of it like splitting a function call in two, or more.

Roughly equivalent to lodash’s _.partial.

const inc = bind(add, 1)

inc(2)
// 3

const incMany = bind(map, inc)

incMany([1, 2, 3])
// [2, 3, 4]

// equivalent:
// bind(map, inc) = map.bind(null, inc)

applyBind(fun, args)

Same as bind, but takes additional arguments as a list rather than as rest parameters.

const inc = applyBind(add, [1])
inc(2)
// 3

curry1(fun, ...args)

A restricted implementation of currying. Creates a function curried for exactly two calls:

const curried = curry1(original, ...originalArgs)
const intermediary = curried(...moreArgs)
intermediary(...finalArgs)
// original(...originalArgs, ...moreArgs, ...finalArgs)

In a language with widespread variadic and optional arguments, such as JavaScript, traditional currying based on argument count is hazardous. Currying for a fixed number of calls and ignoring the argument count is much safer in practice.

function add3 (a, b, c) {return a + b + c}

const addf = curry1(add3)

// is equivalent to:
function addf () {
  return bind(add3, ...arguments)
}

addf(1, 2, 3)()
// 6

addf(1, 2)(3)
// 6

addf(1)(2, 3)
// 6

// with generic currying, this would have returned an intermediary function
// with curry1, two calls always reach the original
addf(1)(2)
// NaN

flip(fun)

Returns a function that passes its arguments to fun in reverse. Only supports functions with variadic arity (from 0 to ∞ arguments).

function add3 (a, b, c) {return a + b + c}

add3('left', '-', 'right')
// 'left-right'

flip(add3)('left', '-', 'right')
// 'right-left'

and(...funs)

Represents the && operation in terms of functions rather than expressions. Returns a new function that &&s calls to the given functions, passing all arguments to each.

Like &&, it’s lazy and aborts early when a function returns a falsy value.

function isPositive (value) {return value > 0}

// this:
const isPosNum = and(isNumber, isPositive)

// is equivalent to:
function isPosNum () {
  return isNumber(...arguments) && isPositive(...arguments)
}

isPosNum(1)
// isNumber(1) && isPositive(1) = true

isPosNum('1')
// isNumber('1') = false

or(...funs)

Represents the || operation in terms of functions rather than expressions. Returns a new function that ||s calls to the given functions, passing all arguments to each.

Like ||, it’s lazy and aborts early when a function returns a truthy value.

// this:
const isPrintable = or(isNumber, isString)

// is equivalent to:
function isPrintable () {
  return isNumber(...arguments) || isString(...arguments)
}

isPrintable(NaN)
// isNumber(NaN) = true

isPrintable([])
// isNumber([]) || isString([]) = false

not(fun)

Represents the ! operation in function terms. Returns a new function that negates the result of the given function.

function eq (a, b) {return a === b}

// this:
const different = not(eq)

// is equivalent to:
function different () {
  return !eq(...arguments)
}

different(1, 2)
// !eq(1, 2) = true

ifelse(test, left, right)

Represents the _ ? _ : _ operation in terms of functions rather than expressions. Returns a new function that calls left if test succeeds and right otherwise, passing all arguments to each.

function bang (a) {return a + '!'}

// this:
const oneone11 = ifelse(isNumber, inc, bang)


// is equivalent to:
function oneone11 () {
  return (isNumber(...arguments) ? inc : bang)(...arguments)
}

oneone11(1)
// isNumber(1) ? inc(1) : _ = 2

oneone11('1')
// isNumber('1') ? _ : bang('1') = '1!'

ifthen(test, fun)

Like ifelse without the else clause.

// this:
ifthen(test, fun)

// is equivalent to:
ifelse(test, fun, () => undefined)

const x = ifthen(isNumber, inc)

x(1)
// inc(1) = 2

x('1')
// undefined

ifonly(test, fun)

Like ifelse but returns the first argument when test fails.

ifonly(test, fun)
// = ifelse(test, fun, x => x)

const x = ifonly(isNumber, inc)

x(1)
// inc(1) = 2

x('1')
// '1'

ifexists(fun)

Like ifthen with an implicit id predicate. The resulting function calls fun when the first argument is truthy, and returns undefined otherwise.

// definition
const ifexists = bind(ifthen, id)

ifexists(fun)
// = ifthen(id, fun)

const x = ifexists(inc)

x(1)
// inc(1) = 2

x(0)
// undefined

cond(...funs)

Represents the Lisp-style cond operation in terms of functions rather than expressions. It’s basically a supercharged ifelse that accepts from 0 to ∞ functions.

Takes any number of functions and divides them into predicate/operator pairs, forming “if/then/else” clauses. The last odd argument becomes a catch-all “else” clause. When given an even number of args, “else” is a no-op that returns undefined.

The resulting function finds an operator by testing arguments against predicates, and returns the operator’s result.

In these examples, all arguments to cond are functions. Comments show equivalent versions expressed with ifelse/ifthen.

cond()
// = noop

cond(isNumber)
// = isNumber

cond(isNumber, dec)
// = ifthen(isNumber, dec)

cond(isNumber, dec, inc)
// = ifelse(isNumber, dec, inc)

const x = cond(
  isNumber,  inc,
  isBoolean, no
)
// = ifelse(isNumber, inc, ifelse(isBoolean, no, noop))

x(1)
// inc(1) = 2

x(true)
// no(true) = false

x([])
// noop() = undefined

pipe(...funs)

Returns a new function that represents composition of the given functions, a common tool in functional programming. When called, it passes all arguments to the first function and pipes the output through the rest.

Flows values left-to-right, in the direction of reading. See comp for the opposite direction.

Equivalent to lodash’s _.flow.

const double = bind(mul, 2)

const x = pipe(add, double)

x(1, 2)
// 6
// = double(add(1, 2))

comp(...funs)

Returns a new function that represents composition of the given functions.

Flows values right-to-left, similarly to direct nested function calls. See pipe for the opposite direction.

const double = bind(mul, 2)

const x = comp(double, add)

x(1, 2)
// 6
// = double(add(1, 2))

seq(...funs)

Represents the , operator in terms of functions rather than expressions.

Returns a new function that runs the given functions in order, passing the same arguments to each, returning the result of the last one. Useful for combining operations that have side effects.

function first (a, b) {
  console.log('first:', a, b)
}

function second (a, b) {
  console.log('second:', a, b)
}

const x = seq(first, second, add)

x(1, 2)
// prints 'first: 1 2'
// prints 'second: 1 2'
// 3

pipeAnd(...funs)

Same as pipe but inserts && between function calls. If one of the chained functions returns a falsy value, others are not invoked. Useful for composing functions that expect truthy values.

function getOne (a) {return a.one}
function getTwo (a) {return a.two}

const x = pipeAnd(getOne, getTwo)

x({one: {two: 2}})
// 2

x({one: NaN})
// NaN

compAnd(...funs)

Same as comp but inserts && between function calls. If one of the chained functions returns a falsy value, others are not invoked. Useful for composing functions that expect truthy values.

function getOne (a) {return a.one}
function getTwo (a) {return a.two}

const x = compAnd(getTwo, getOne)

x({one: {two: 2}})
// 2

x({one: NaN})
// NaN

juxt(...funs)

Returns a function that calls all funs, returning the results as a list. It passes the same arguments to each fun.

Name taken from a similar function in Clojure. Short for “juxtapose”. Equivalent to lodash’s _.over.

const x = juxt(add, sub)

x(1, 2)
// [3, -1]

rest(fun)

Returns a function that collects its arguments and passes them to fun as the first argument. An opposite of spread.

rest(id)(1, 2, 3)
// [1, 2, 3]

// same without rest:
id([1, 2, 3])
// [1, 2, 3]

spread(fun)

Returns a function that takes arguments as one list-like value and spreads it over fun as multiple arguments. An opposite of rest.

function sum () {
  return foldl(add, 0, arguments)
}

spread(sum)([1, 2, 3])
// 6

// same without spread:
sum(1, 2, 3)
// 6

alter(fun, ...args)

Spiritual complement of bind. Creates a function that takes one value and calls fun with that value and ...args. Useful for transforms where arguments 1..N are known in advance. The resulting function ignores all arguments after the first.

const sum = bind(foldl, 0, add)

const x = alter(sum, 10, 20)

x(1)
// sum(1, 10, 20) = 31

x(1, 'ignored arg')
// sum(1, 10, 20) = 31

revise(transforms, fun)

Creates a function that will revise its arguments before calling fun. transforms is a list of functions that are used to rewrite the corresponding arguments, positionally. The resulting function ignores arguments beyond the available transforms.

const double = bind(mul, 2)

const x = revise([inc, double], add)

x(10, 20)
// add(inc(10), double(20)) = add(11, 40) = 51

x(10, 20, 'ignored arg')
// add(inc(10), double(20)) = add(11, 40) = 51

fanout(transforms, fun)

Creates a function that will magnify its inputs before calling fun. transforms is a list of functions that are called with all available arguments; the list of their results is then spread over fun.

const sum = bind(foldl, 0, add)

const a = fanout([add, sub], sum)

a(10, 20)
// sum(add(10, 20), sub(10, 20)) = sum(30, -10) = 20

const double = bind(mul, 2)

const b = fanout([double, double], sum)

b(10)
// sum(double(10), double(10)) = sum(20, 20) = 40

funnel(value, funs)

Similar to pipe, but immediate. Instead of creating a function, it flows value through funs left-to-right and returns the result.

const double   = bind(mul, 2)
const negative = bind(mul, -1)

funnel(10, [])
// 10

funnel(10, [double, negative])
// negative(double(10)) = -20

Bool

Boolean tests.


truthy(value)

Aliases: truthy, bool.

Same as !!.

truthy(null)
// false

truthy(1)
// true

falsy(value)

Aliases: falsy, negate.

Same as !.

falsy(null)
// true

falsy(1)
// false

is(one, other)

Same as ES2015’s Object.is. Like === but considers NaN equal to itself.

Used internally for identity tests. Recommended over === in most practical scenarios.

is(1, '1')
// false

is(NaN, NaN)
// true

isNumber(value)

isNumber(1)
// true

isFinite(value)

Same as ES2015’s Number.isFinite.

Recommended over isNumber in most practical scenarios.

isFinite(1)
// true
isFinite('1') || isFinite(NaN)
// false

isNatural(value)

True if value is a natural number: a positive integer, starting with 0.

isNatural(0)
// true
isNatural(1)
// true
isNatural(-1) || isNatural(1.1) || isNatural('1')
// false

isNaN(value)

Same as ES2015’s Number.isNaN. True if value is really, strictly NaN. Unlike the old global isNaN, doesn’t coerce non-numbers.

isNaN(NaN)
// true
isNaN(undefined)
// false

isString(value)

isString('blah')
// true

isBoolean(value)

isBoolean(false)
// true

isSymbol(value)

isSymbol(Symbol('blah'))
// true

isFunction(value)

isFunction(isFunction)
// true

isObject(value)

True if value has the type 'object' and isn’t null. This includes plain dicts, arrays, regexes, user-defined “classes”, built-in classes, and so on. Doesn’t count functions as objects, even though technically they are.

Note: this is not equivalent to lodash’s _.isObject, which counts functions as objects. See isComplex for that.

isObject('blah')
// false

isObject(/blah/)
// true

isObject([])
// true

isObject(Object.create(null))
// true

isObject(() => {})
// false

isComplex(value)

Definition:

const isComplex = or(isObject, isFunction)

This includes all objects in the true JavaScript sense. Functions are technically objects, as they have properties and may be mutated.


isPrimitive(value)

Definition:

const isPrimitive = not(isComplex)

This includes:


isDict(value)

Aliases: isDict, isPlainObject.

True if value is a normal, honest-to-goodness dictionary and not something fancy-shmancy.

isDict({})
// true

isDict(Object.create(null))
// true

isDict(Object.create({}))
// false

isDict([])
// false

isArray(value)

True if value inherits from Array.prototype.

isArray([])
// true

isList(value)

True if value looks like a linear, ordered list. This includes arguments, NodeLists, and so on. Used internally for most list checks. Note that this doesn’t include strings.

isList([])
// true

const args = function () {return arguments}()
isList(args)
// true

isList(document.querySelectorAll('div'))
// true

isList('str')
// false

isRegExp(value)

isRegExp(/blah/)
// true

isPromise(value)

True if the value quacks like an ES2015 Promise. The value doesn’t have to belong to any specific promise implementation, native or otherwise.

isPromise(Promise.resolve('test'))
// true

isPromise({then () {}, catch () {}})
// true

isPromise({then () {}})
// false

isNil(value)

Definition:

function isNil (value) {
  return value == null
}

This includes null and undefined.


testBy(pattern, value)

Limited form of pattern testing. Together with ES2015 destructuring, it lets you crudely approximate pattern matching, a feature common in functional languages but missing from JavaScript.

Tests value against pattern. The nature of the test depends on the provided pattern.

// function -> apply as-is

testBy(inc, 10)            =  11

// primitive -> test for identity via `is`

testBy(null, x)            =  is(null, x)
testBy(1, x)               =  is(1, x)
testBy(NaN, x)             =  is(NaN, x)

// regex -> call `RegExp.prototype.test`

testBy(/blah/, x)          =  /blah/.test(x)

// list ->
//   checks that input is a list
//   each property tests the corresponding input property

testBy([], x)              =  isList(x)
testBy([/blah/], x)        =  isList(x) && /blah/.test(x[0])
testBy([/blah/, 'c'], x)   =  isList(x) && /blah/.test(x[0]) && is(x[1], 'c')

// dictionary ->
//   checks that input is a dict
//   each property tests the corresponding input property

testBy({}, x)              =  isObject(x)
testBy({one: /blah/}, x)   =  isObject(x) && /blah/.test(x.one)
testBy({two: isArray}, x)  =  isObject(x) && isArray(x.two)
testBy({a: {b: 'c'}}, x)   =  isObject(x) && isObject(x.a) && is(x.a.b, 'c')

test(pattern)

curry1-version of testBy. Takes a pattern and returns a function that tests any value against that pattern.

test(isNumber)        =  isNumber

test(null)            =  x => is(x, null)
test(1)               =  x => is(x, 1)
test(NaN)             =  x => is(x, NaN)

test(/blah/)          =  x => /blah/.test(x)

test([])              =  x => isList(x)
test([/blah/])        =  x => isList(x) && /blah/.test(x[0])
test([/blah/, 'c'])   =  x => isList(x) && /blah/.test(x[0]) && is(x[1], 'c')
test({})              =  x => isObject(x)

test({one: /blah/})   =  x => isObject(x) && /blah/.test(x.one)
test({two: isArray})  =  x => isObject(x) && isArray(x.two)
test({a: {b: 'c'}})   =  x => isObject(x) && isObject(x.a) && is(x.a.b, 'c')

Using Patterns

Using test and ES2015 destructuring to approximate pattern matching:

const {test, ifthen, isNumber} = require('fpx')

// Util

function match (pattern, func) {
  return ifthen(test(pattern), func)
}

// Usage

const x = match({type: 'double', value: isNumber}, ({value}) => value * 2)

x('test')
// undefined

x({type: 'double', value: 10})
// 20

testAnd(...patterns)

Converts each pattern to a test and composes them with and. The resulting function will test its argument against each pattern and decide if it matches all of them.

const x = testAnd(isString, /10/)

/10/.test(1001)
// true

x(1001)
// testBy(isString, 1001)  =  false

x('1001')
// testBy(isString, '1001') && testBy(/10/, '1001')  =  true

testOr(...patterns)

Converts each pattern to a test and composes them with or. The resulting function will test its argument against each pattern and decide if it matches some of them.

const x = testOr(truthy, 0)

x(null)
// testBy(truthy, null) || testBy(0, null)  =  false

x(1)
// testBy(truthy, 1)  =  false

x(0)
// testBy(truthy, 0) || testBy(0, 0)  =  true

testArgsAnd(...patterns)

Similar to testAnd but applies tests positionally: first pattern to first argument, second pattern to second argument, and so on. The resulting function returns true if every pattern matches its argument, and false otherwise.

const x = testArgsAnd(isFinite, isFinite)

x(10, Infinity)
// testBy(isFinite, 10) && testBy(isFinite, Infinity)  =  false

x(10, 20)
// testBy(isFinite, 10) && testBy(isFinite, 20)  =  true

testArgsOr(...patterns)

Similar to testOr but applies tests positionally: first pattern to first argument, second pattern to second argument, and so on. The resulting function returns true if at least one pattern matches its argument, and false otherwise.

const x = testArgsOr(isFinite, /test/)

x(null, 100)
// testBy(isFinite, null) || testBy(/test/, 100)  =  false

x(10, 100)
// testBy(isFinite, 10)  =  true

x(null, 'test')
// testBy(isFinite, null) || testBy(/test/, 'test')  =  true

List

List manipulation utils. Like all other fpx functions, they treat their arguments as immutables and never modify them.


list(...values)

Same as ES2015’s Array.of. Returns its arguments as an Array.

list()
// []

list(1)
// [1]

list(1, [2])
// [1, [2]]

foldl(fun, accumulator, list)

Similar to Array#reduce, but with an FP-friendly argument order, more suitable for currying and partial application. The accumulator argument is mandatory.

foldl(add, 10, [1, 2, 3])
// 10 + 1 + 2 + 3 = 16

foldr(fun, accumulator, list)

Similar to Array#reduceRight, but with an FP-friendly argument order. The accumulator argument is mandatory.

foldr(sub, 100, [1, 5, 20])
// 100 - 20 - 5 - 1 = 74

map(fun, list)

Like Array#map, but with an FP-friendly argument order.

const double = bind(mul, 2)

map(double, [1, 2, 3])
// [2, 4, 6]

filter(test, list)

Like Array#filter, but with an FP-friendly argument order.

filter(isBoolean, [1, 2, true, false])
// [true, false]

filter(test({val: id}), [{val: 0}, null, {val: 1}])
// [{val: 1}]

find(test, list)

Like Array#find, but with an FP-friendly argument order.

find(isBoolean, [1, 2, true, false])
// true

find(test({val: id}), [{val: 0}, null, {val: 1}])
// {val: 1}

every(test, list)

Like Array#every, but with an FP-friendly argument order.

every(isBoolean, [])
// true

every(isBoolean, [true, false])
// true

every(isBoolean, [true, false, 10, 20])
// false

some(test, list)

Like Array#some, but with an FP-friendly argument order.

some(isBoolean, [])
// false

some(isBoolean, [10, 20])
// false

some(isBoolean, [true, false, 10, 20])
// true

procure(fun, list)

Similar to find, but returns the result of fun rather than the element it was called on.

const double = bind(mul, 2)

procure(double, [0, 0, 10, 100])
// double(10) = 20

includes(list, value)

Similar to ES2015’s Array#includes.

includes([3, 2, 1], NaN)
// false

includes([3, 2, NaN], NaN)
// true

indexOf(list, value)

Similar to Array#indexOf. Unlike Array#indexOf, it detects NaN.

indexOf([3, 2, 1], 1)
// 2

indexOf([3, 2, NaN], NaN)
// 2

slice(value, [start], [end])

Like Array#slice, but with the sliceable as the first argument.

slice([1, 2, 3], 2)
// [3]

slice('hello world', 3, 5)
// ['l', 'o']

append(list, value)

Returns a version of list with value appended at the end.

append([1, 2], 3)
// [1, 2, 3]

prepend(list, value)

Returns a version of list with value prepended at the start.

prepend([2, 3], 1)
// [1, 2, 3]

remove(list, value)

Returns a version of list with one occurrence of value removed. May return the original list.

remove(['one', 'two', 'three'], 'two')
// ['one', 'three']

remove(['one', 'two', 'one'], 'one')
// ['two', 'one']

removeAtIndex(list, index)

Returns a version of list with the value at index removed if and only if index is a natural integer within the bounds of list. With any other input, returns the list argument, coercing it to a list if necessary.

remove(['one', 'two', 'three'], 0)
// ['two', 'three']

remove(['one', 'two', 'three'], 1)
// ['one', 'three']

remove(['one', 'two', 'three'], 10)
// ['one', 'two', 'three']

adjoin(list, value)

Appends value to list, duplicate-free. Returns the same list if it already includes value.

adjoin([10, 20], 30)
// [10, 20, 30]

adjoin([10, 20, 30], 20)
// [10, 20, 30]

toggle(list, value)

Appends or removes value, depending on whether it’s already included.

toggle([10, 20], 30)
// [10, 20, 30]

toggle([10, 20, 30], 30)
// [10, 20]

concat(...lists)

Concatenates the given lists into one list. Ignores non-list arguments.

This is intentionally different from Array#concat and, by extension, lodash’s _.concat. They inherited Scheme’s mistakes and are hazardous. They accept both list and non-list arguments, concatenating lists and appending other values. This often leads to surprising results.

fpx’s concat is more intuitive and therefore safer to use.

concat()
// []

concat([10], [20], [30])
// [10, 20, 30]

concat([10, 20], 30)
// [10, 20]

flat(list)

Deeply flattens the given list.

flat([1, [2], [[3]]])
// [1, 2, 3]

head(list)

Returns the first element of the given list.

head()
// undefined

head([1, 2, 3])
// 1

head('str')
// undefined

tail(list)

Returns all but first element of the given list.

tail()
// []

tail([1, 2, 3])
// [2, 3]

tail('str')
// []

init(list)

Returns all but last element of the given list.

init()
// []

init([1, 2, 3])
// [1, 2]

init('str')
// []

last(list)

Returns the last element of the given list.

last()
// undefined

last([1, 2, 3])
// 3

last('str')
// undefined

reverse(list)

Returns a version of list with the elements reversed end-to-start. If called with a non-list, returns an empty list.

reverse()
// []

reverse([10, 20, 30])
// [30, 20, 10]

reverse('str')
// []

Dict

Utils for dealing with dictionaries (“objects”) and properties in general. Like all other fpx functions, they treat their arguments as immutables and never modify them.


get(value, key)

Reads property key from value. Similar to the bracket notation: value[key]. Advantages over the bracket notation: safe to use on null or undefined values; compatible with function composition.

get()
// undefined

get(null, 'one')
// undefined

get({one: 1}, 'one')
// 1

get('str', 'length')
// 3

scan(value, ...path)

Like get but takes many keys and reads a nested property at that path.

scan()
// undefined

scan(null)
// null

scan(null, 'one')
// undefined

scan({one: 1}, 'one')
// 1

scan({one: {two: 2}}, 'one', 'two')
// 2

getIn(value, path)

Like scan but expects the entire path as the second argument. Useful when path is determined dynamically.

getIn(1, [])
// 1

getIn({one: {two: 2}}, ['one', 'two'])
// 2

getAt(path, value)

Like getIn but expects the entire path as the first argument. Useful in function composition contexts when path is known in advance.

getAt([], 1)
// 1

getAt(['one', 'two'], {one: {two: 2}})
// 2

const from = curry1(getAt)

const read = from(['one', 'two'])

read({one: {two: 2}})
// 2

mapVals(fun, value)

Maps value to a dictionary with the same properties, transforming their values via fun.

Similar to lodash’s _.mapValues, but with an FP-friendly argument order.

function bang (a) {return a + '!'}

mapVals(bang, {ping: 'ping', pong: 'pong'})
// {ping: 'ping!', pong: 'pong!'}

mapKeys(fun, value)

Like mapVals, but alters keys rather than values.

Similar to lodash’s _.mapKeys, but with an FP-friendly argument order.

mapKeys(last, {one: 'one', two: 'two'})
// {e: 'one', o: 'two'}

Coll

Utils for dealing with collections (lists and dicts). Like all other fpx functions, they treat their arguments as immutables and never modify them.


keys(value)

Like Object.keys but safe to use on primitives.

Same as lodash’s _.keys.

keys()
// []

keys({one: 1, two: 2})
// ['one', 'two']

keys(keys)
// []

values(value)

Returns the values of all properties of value as a list. Safe to use on primitives.

Same as lodash’s _.values.

values()
// []

values({one: 1, two: 2})
// [1, 2]

values(values)
// []

size(value)

Depends on value‘s type:

Safe to use on primitives.

size([10, 20])
// 2

size({one: 1, two: 2})
// 2

size()
// 0

size(size)
// 0

Ops

Operator-style functions.


add(a, b)

Same as +.

add(1, 2)
// 1 + 2 = 3

sub(a, b)

Same as -.

sub(2, 1)
// 2 - 1 = 1

mul(a, b)

Same as *.

mul(10, 20)
// 10 * 20 = 200

div(a, b)

Same as /.

div(10, 20)
// 10 / 20 = 0.5

inc(num)

Increments by 1.

inc(1)
// 1 + 1 = 2

dec(num)

Decrements by 1.

dec(2)
// 2 - 1 = 1

Misc

Uncategorised utils.


id(value)

Identity function: returns its argument unchanged. Useful in boolean contexts.

id('first', 'second', 'third')
// 'first'

di(_, value)

Returns its second argument unchanged. Useful in function composition contexts.

di('first', 'second', 'third')
// 'second'

val(value)

“Constant” function. Returns a function that always returns the passed value. Useful for dealing with functional APIs when values are known in advance.

Equivalent to lodash’s _.constant.

const one = val(1)

one()
// 1

one(100)
// 1

maskBy(pattern, value)

Overlays pattern on value. The nature of the result depends on the provided pattern.

// function -> apply as-is

maskBy(isNumber, x)        =  isNumber(x)

// primitive -> replace value

maskBy(null, x)            =  null
maskBy(1, x)               =  1
maskBy(NaN, x)             =  NaN

// regex -> call `RegExp.prototype.test`

maskBy(/blah/, x)          =  /blah/.test(x)

// list -> map to corresponding input properties, masking them

maskBy([], x)              =  []
maskBy([/blah/], x)        =  [/blah/.test(get(x, 0))]
maskBy([/blah/, 'c'], x)   =  [/blah/.test(get(x, 0)), 'c']

// dict -> map to corresponding input properties, masking them

maskBy({}, x)              =  {}
maskBy({one: /blah/}, x)   =  {one: /blah/.test(get(x, 'one'))}
maskBy({two: isArray}, x)  =  {two: isArray(get(x, 'two'))}
maskBy({a: {b: 'c'}}, x)   =  {a: {b: 'c'}}

mask(pattern)

curry1-version of maskBy. Takes a pattern and returns a function that overlays that pattern on any value.

mask(isNumber)        =  isNumber

mask(null)            =  val(null)
mask(1)               =  val(1)
mask(NaN)             =  val(NaN)

mask(/blah/)          =  x => /blah/.test(x)

mask([])              =  _ => []
mask([/blah/])        =  x => [/blah/.test(get(x, 0))]
mask([/blah/, 'c'])   =  x => [/blah/.test(get(x, 0)), 'c']

mask({})              =  _ => ({})
mask({one: /blah/})   =  x => ({one: /blah/.test(get(x, 'one'))})
mask({two: isArray})  =  x => ({two: isArray(get(x, 'two'))})
mask({a: {b: 'c'}})   =  x => ({a: {b: 'c'}})

noop

Empty function. Functional equivalent of ; or undefined. Useful in composition contexts.

noop()
// undefined

ifthen(a, b) = ifelse(a, b, noop)

rethrow(val)

Same as throw but can be used as an expression or composed with other funs.

// Expression
const x = someTest ? someValue : rethrow(Error('unreachable'))

// Composition
Promise.reject(Error('fail')).catch(pipe(log, rethrow))

validate(test, value)

If value doesn’t satisfy the provided test function, raises an exception with a message including test‘s name and the failing value.

Convenient and minification-friendly way to assert values.

validate(isFunction, x => x)
// undefined

validate(isFunction, 1)
// Uncaught Error: Expected 1 to satisfy test isFunction

validateEach(test, list)

Same as validate but asserts each value in the provided list.

validateEach(isFunction, [x => x])
// undefined

validateEach(isFunction, [1])
// Uncaught Error: Expected 1 at index 0 to satisfy test isFunction

Author

mitranim.com