111 lines
3.8 KiB
JavaScript
111 lines
3.8 KiB
JavaScript
import { Result } from './result.js'
|
|
|
|
export const identity = x => x
|
|
|
|
// functions
|
|
export function curryN(arity, func) {
|
|
return function curried(...args) {
|
|
if (args.length >= arity) {
|
|
return func.apply(this, args)
|
|
} else {
|
|
return function(...args2) {
|
|
return curried.apply(this, args.concat(args2))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export const curry = fn => curryN(fn.length, fn)
|
|
export const flip = fn => curry((a, b) => fn(b, a))
|
|
export const tap = curry((fn, val) => {
|
|
fn(val)
|
|
return val
|
|
})
|
|
|
|
export const always = x => () => x
|
|
export const pipe = (...f) => v => reduce(applyTo, v, f)
|
|
export const apply = fn => args => fn.apply(null, args)
|
|
export const applyTo = curry((v, fn) => fn(v))
|
|
export const useWith = curry((fn, tfns) =>
|
|
curryN(
|
|
tfns.length,
|
|
(...args) => pipe(enumerate, map(([i, a]) => tfns[i](a)), fn)(args)
|
|
))
|
|
|
|
export const converge = (fn, [head, ...rest]) => curryN(
|
|
head.length,
|
|
(...args) => pipe(...rest, fn)(head(...args))
|
|
)
|
|
|
|
export const diverge = (fn, tfns) => pipe(applyTo, flip(map)(tfns), apply(fn))
|
|
|
|
// types
|
|
export const isArray = Array.isArray
|
|
export const isNil = v => !v
|
|
export const is = curry((type, value) => value instanceof type)
|
|
|
|
// branching
|
|
export const ifElse = curry((p, ft, ff, v) => p(v) ? ft(v) : ff(v))
|
|
export const when = curry((p, f, v) => ifElse(p, f, identity, v))
|
|
export const unless = curry((p, f, v) => ifElse(p, identity, f, v))
|
|
|
|
// predicates
|
|
export const and = (...booleans) => booleans.every(identity)
|
|
export const or = (...booleans) => booleans.some(identity)
|
|
export const isOk = value => !is(Result, value) || value.isOk()
|
|
|
|
// classes
|
|
export const construct = Type => args => new Type(...args)
|
|
|
|
// strings
|
|
export const split = curry((delim, v) => v.split(delim))
|
|
|
|
// arrays
|
|
export const length = v => v.length
|
|
export const len = length
|
|
export const of = unless(isArray, value => ([value]))
|
|
export const concat = curry((a, b) => b.concat(a))
|
|
export const take = curry((n, value) => value.slice(0, n))
|
|
export const drop = curry((n, value) => value.slice(n))
|
|
export const nth = curry((index, value) => value[index])
|
|
export const head = nth(0)
|
|
export const tail = drop(1)
|
|
export const map = curry((fn, v) => v.map(fn))
|
|
export const filter = curry((fn, v) => v.filter(fn))
|
|
export const reduce = curry((fn, init, v) => v.reduce(fn, init))
|
|
export const find = curry((fn, v) => v.find(fn))
|
|
export const join = curry((sep, v) => v.join(sep))
|
|
export const rev = v => v.slice().reverse()
|
|
export const prepend = curry((value, iter) => [value, ...iter])
|
|
export const append = curry((value, iter) => [...iter, value])
|
|
export const enumerate = value => value.map((v, i) => ([i, v]))
|
|
export const flatten = curry((n, v) => v.flat(n))
|
|
export const update = curry((index, value, arr) => arr.toSpliced(index, 1, value))
|
|
|
|
// objects
|
|
const makePath = unless(isArray, split('.'))
|
|
export const assoc = curry((key, value, obj) => ({ ...obj, [key]: value }))
|
|
export const assocPath = curry((key, value, obj) => pipe(
|
|
makePath,
|
|
rev,
|
|
reduce((acc, val) => fromEntries([[val, acc]]), value),
|
|
mergeLeft(obj)
|
|
)(key))
|
|
|
|
export const prop = curry((key, obj) => obj && key && obj[key])
|
|
export const path = curry((key, obj) => reduce(flip(prop), obj, makePath(key)))
|
|
export const mergeLeft = curry((a, b) => ({ ...b, ...a }))
|
|
export const mergeRight = flip(mergeLeft)
|
|
export const keys = Object.keys
|
|
export const values = Object.values
|
|
export const entries = Object.entries
|
|
export const fromEntries = Object.fromEntries
|
|
|
|
// lenses
|
|
export const lens = curry((get, set) => ({ get, set }))
|
|
export const lensPath = path => lens(path(path), assocPath(path))
|
|
export const lensIndex = index => lens(nth(index), update(index))
|
|
export const view = curry(({ get }, obj) => get(obj))
|
|
export const set = curry((l, value, obj) => over(l, always(value), obj))
|
|
export const over = curry(({ get, set }, fn, obj) => set(fn(get(obj)), obj))
|
|
|