Skip to content

Instantly share code, notes, and snippets.

@mrosata
Last active January 15, 2023 01:47
Show Gist options
  • Save mrosata/0d54c552f297cf638bd719f7558478ac to your computer and use it in GitHub Desktop.
Save mrosata/0d54c552f297cf638bd719f7558478ac to your computer and use it in GitHub Desktop.
A subset of the Ramda library written using arrow functions, "lamda-ramda". The purpose of this is fun and to use in environments where importing 3rd party libs isn't allowed. Feel free to add to this.
const R = new LaRamda()
/**
* A subset of custom implementations of functions from
* the Ramda library. (all in Lamda form)
* - thanks to @xgrommx for uniq, intersection, where, evolve,
* applySpec, defaultTo, both, either, cond, zipWith
*/
function LaRamda () {
const I = x => x
const K = x => y => x
const S = f => g => x => f(x)(g(x))
this.identity = I
this.always = K
this.tap = S(K)
const _ifElse = (pred, ifTrue, ifFalse) => x => pred(x) ? ifTrue(x) : ifFalse(x)
this.curryN = (n, fn, ...args) => args.length < n ?
this.curryN.bind(this, n, fn, ...args) : fn(...args)
this.curry = (fn, ...args) => _ifElse(
K(fn.length > args.length),
K(this.curry.bind(this, fn, ...args)),
K(fn(...args))
)
this.curry = (fn) => (...args) => fn.length > args.length ? fn.bind(fn, ...args) : fn(...args)
this.concat = this.curry((a, b) => a.concat(b))
this.apply = this.curry((fn, args) => fn(...args))
this.prop = this.curry((k, obj) => obj[k])
this.of = (...args) => [...args]
this.head = ([a, ...xs]) => a
this.last = (xs) => this.concat([], xs).slice(-1).pop()
this.tail = (x, ...xs) => this.concat([], xs)
this.init = (xs) => this.concat([], xs).slice(0, -1)
this.map = this.curry((fn, xs) => xs.map(fn))
this.reduce = this.curry((fn, def) => xs => this.concat([], xs).reduce(fn, def))
this.reduceR = this.curry((fn, def) => xs => this.concat([], xs).reduceRight(fn, def))
this.uniq = this.uniq = arr => [...new Set(arr)]
this.intersection = a => b => a.filter(Set.prototype.has, new Set(b))
this.join = this.curry((sep, xs) => this.concat([], xs).join(sep))
this.prepend = this.curry((x, xs) => [x, ...xs])
this.compose = (...fns) => (...input) => this.reduceR(
(x, fn) => fn(x), this.last(fns)(...input))(this.init(fns)
)
this.equals = this.curry((a, b) => a === b)
this.nthArg = n => (...args) => args[n]
this.filter = this.curry((fn, xs) => xs.filter(fn))
this.repeat = this.curry((x, n) => Array(n).fill(x))
this.zip = xs => this.compose(
this.filter(I),
this.map((y, i) => xs.length >= i ? [xs[i], y] : null)
)
this.pair = this.curry((v, i) => [v, i])
this.subtract = this.curry((a, b) => a - b)
this.both = (a, b) => (...args) => [a, b].every(f => f(...args))
this.either = (a, b) => (...args) => [a, b].some(f => f(...args))
this.defaultTo = n => this.ifElse(Boolean, I, K(n))
this.ifElse = this.curry(_ifElse)
this.when = this.curry((pred, ifTrue, x) => pred(x) ? ifTrue(x) : x)
this.lt = this.curry((n1, n2) => n1 < n2)
this.gt = n => this.complement(this.lt(n))
this.lte = this.curry((n1, n2) => n1 <= n2)
this.gte = n => this.complement(this.lte(n))
this.length = this.prop('length')
this.not = x => !x
this.complement = pred => x => this.not(pred(x))
this.isNil = x => x === null || typeof x === 'undefined'
this.either = this.curry((pred1, pred2) => x => !!(pred1(x) || pred2(x)))
this.has = this.curry((prop, obj) => obj.hasOwnProperty(prop))
this.is = this.curry((cons, t) => this.not(this.isNil(t)) && t.constructor === cons)
this.propSatisfies = this.curry((pred, key, obj) =>
this.compose(pred, this.prop(key))(obj))
this.converge = (convergeOnFn, argFns) => (...args) => this.apply(convergeOnFn)(
this.map((fn, i) => this.apply(fn)(args))(argFns))
this.useWith = (useOnFn, argFns) => (...args) => this.apply(useOnFn)(
this.map((arg, i) => (argFns[i] || I)(arg))(args)
)
this.takeWhile = pred => this.compose(this.prop('v'), this.reduce(
(acc, x) => !acc.f && pred(x) ?
{ f: false, v: [...acc.v, x] } :
{ v: acc.v, f: true }, { v: [], f: false }
))
this.groupWith = pred => this.compose(this.prop('v'), this.reduce(
(acc, x) =>
typeof acc.p !== 'undefined' && pred(acc.p, x) ?
{ p: acc.p, v: [...acc.v.slice(0, -1), [].concat(...acc.v.slice(-1), [x]) ] } :
{ p: x, v: [...acc.v, [x]] }, { v: [] }
))
this.where = this.curry((predicateObj, obj) => {
return Reflect.ownKeys(obj).every(key => {
return predicateObj[key](obj[key])
});
})
this.unless = this.curry((condition, f) => this.cond([
[(...args) => condition(...args), I],
[K(true), (...args) => f(...args)],
]))
this.applySpec = transformObj => (...args) => {
return Reflect.ownKeys(transformObj).reduce((acc, key) => {
return Object.assign({}, acc, {
[key]: typeof transformObj[key] === 'function' ?
transformObj[key](...args) :
this.applySpec(transformObj[key])(...args),
})
}, {});
}
const _evolve = transformObj => obj => {
return Reflect.ownKeys(obj).reduce((acc, key) => {
return Object.assign({}, acc, {
[key]: transformObj[key] ?
(typeof transformObj[key] === 'function'
? transformObj[key](obj[key])
: _evolve(transformObj[key])(obj[key])) : obj[key],
})
}, {});
}
this.zipWith = f => a => b => {
const size = Math.min(a.length, b.length);
const [x, y] = [a, b].map(xs => xs.slice(0, size));
return x.reduce((acc, next, i) => {
return [...acc, f(next)(y[i])];
}, []);
}
this.cond = conditions => {
return (...args) => {
for (const condition of conditions) {
if (condition[0](...args)) {
return condition[1](...args)
}
}
}
}
this.evolve = this.curry(_evolve)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment