Last active
August 2, 2022 05:50
-
-
Save branneman/7b9571f53e2c98c2a40f1cd572002f9e to your computer and use it in GitHub Desktop.
JavaScript functional programming library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { curryN, curry } = require('./curry') // https://gist.github.com/branneman/4ffb7ec3fc4a2091849ba5d56742960c | |
// Typechecks | |
const isUndef = x => typeof x === 'undefined' | |
const isNull = x => x === null | |
const isBool = x => typeof x === 'boolean' | |
const isNum = x => typeof x === 'number' && isFinite(x) | |
const isInt = x => typeof x === 'number' && isFinite(x) && Math.floor(x) === x | |
const isStr = x => typeof x === 'string' | |
const isArr = x => Array.isArray(x) | |
const isRegExp = x => isObj(x) && x instanceof RegExp | |
const isFunc = x => typeof x === 'function' | |
const isSymbol = x => typeof x === 'symbol' | |
const isObj = x => x === Object(x) && !isArr(x) && !isFunc(x) && !isSymbol(x) | |
// Array higher-order | |
const map = curry((fn, list) => list.map(fn)) | |
const filter = curry((fn, list) => list.filter(fn)) | |
const foldl = curry((fn, init, list) => list.reduce(fn, init)) | |
const foldr = curry((fn, init, list) => list.reduceRight(fn, init)) | |
const find = curry((fn, list) => list.find(fn)) | |
const sort = curry((fn, list) => list.slice().sort(fn)) | |
const includes = curry((fn, list) => list.includes(fn)) | |
// Array | |
const length = list => list.length | |
const nth = curry((key, list) => list[key]) | |
const slice = curry((from, to, list) => list.slice(from, to)) | |
const range = curry((from, to) => map(add(from), [...Array(to - from).keys()])) | |
const head = nth(0) | |
const init = slice(0, -1) | |
const tail = slice(1, Infinity) | |
const last = slice(-1, Infinity) | |
const concat = curry((a, b) => a.concat(b)) | |
const flatten = foldl(concat, []) | |
const reverse = list => list.slice().reverse() | |
const distinct = xs => foldl((acc, curr) => (acc.indexOf(curr) < 0) ? acc.concat([curr]) : acc, [], xs) | |
const update = curry((key, val, list) => ((list[key] = val), list)) | |
// Logic & Relation | |
const not = a => !a | |
const and = curry((a, b) => a && b) | |
const or = curry((a, b) => a || b) | |
const eq = curry((left, right) => left === right) | |
const lt = curry((left, right) => left < right) | |
const lte = curry((left, right) => left <= right) | |
const gt = curry((left, right) => left > right) | |
const gte = curry((left, right) => left >= right) | |
const min = curry((a, b) => (b < a ? b : a)) | |
const max = curry((a, b) => (b > a ? b : a)) | |
const defaultTo = x => y => isUndef(y) || isNull(y) ? x : y | |
// Math | |
const add = curry((a, b) => a + b) | |
const subtract = curry((a, b) => a - b) | |
const multiply = curry((a, b) => a * b) | |
const divide = curry((a, b) => a / b) | |
const inc = add(1) | |
const dec = add(-1) | |
const modulo = curry((a, b) => a % b) | |
const negate = n => -n | |
const sum = foldl(add, 0) | |
const product = foldl(multiply, 1) | |
const mean = list => sum(list) / length(list) | |
const median = list => | |
length(list) % 2 | |
? list[(length(list) - 1) / 2] | |
: mean([list[length(list) / 2 - 1], list[length(list) / 2]]) | |
// String | |
const test = curry((re, str) => re.test(str)) | |
const match = curry((re, str) => str.match(re) || []) | |
const replace = curry((re, replacement, str) => str.replace(re, replacement)) | |
const lower = s => s.toLowerCase(s) | |
const upper = s => s.toUpperCase(s) | |
// Object | |
const has = curry((key, obj) => Object.prototype.hasOwnProperty.call(obj, key)) | |
const keys = obj => Object.keys(obj) | |
const values = obj => Object.values(obj) | |
const entries = obj => Object.entries(obj) | |
const prop = curry((key, obj) => obj[key]) | |
const assoc = curry((key, val, obj) => ((obj[key] = val), obj)) | |
const pick = curry((keys, obj) => foldl( | |
(acc, curr) => obj[curr] ? ((acc[curr] = obj[curr]), acc) : acc, | |
{}, keys)) | |
// Lenses | |
const lens = curry((get, set) => ({ get, set })) | |
const view = curry((lens, obj) => lens.get(obj)) | |
const set = curry((lens, val, obj) => lens.set(val, obj)) | |
const over = curry((lens, fn, obj) => set(lens, fn(view(lens, obj)), obj)) | |
const lensIndex = key => lens(nth(key), update(key)) | |
const lensProp = key => lens(prop(key), assoc(key)) | |
// Function | |
const compose = (...fns) => | |
foldl((f, g) => (...args) => f(g(...args)), head(fns), tail(fns)) | |
const pipe = (...fns) => compose(...reverse(fns)) | |
const apply = curry((fn, xs) => fn.apply(null, xs)) | |
const complement = fn => compose(not, fn) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment