Skip to content

Instantly share code, notes, and snippets.

@masaeedu
Last active August 8, 2019 17:41
Show Gist options
  • Save masaeedu/be84c9ac2b54fdb45321c8fb264f97ca to your computer and use it in GitHub Desktop.
Save masaeedu/be84c9ac2b54fdb45321c8fb264f97ca to your computer and use it in GitHub Desktop.
const { cata } = require("@masaeedu/fp")
const { adt, match } = require("@masaeedu/adt")
// All of these are common, reusable utilities you could get from a library
const classes = (() => {
const foldable = ({ foldMap }) => {
const fold = fn.flip(foldMap)(fn.identity)
return { fold }
}
const bifoldable = ({ bifoldMap }) => {
const lfoldMap = m => f => bifoldMap(m)(f)(fn.identity)
const rfoldMap = m => f => bifoldMap(m)(fn.identity)(f)
return { lfoldMap, rfoldMap }
}
return { foldable, bifoldable }
})()
const fn = (() => {
const identity = x => x
const compose = f => g => x => f(g(x))
const flip = f => x => y => f(y)(x)
return { identity, compose, flip }
})()
const maybe = adt({ nothing: [], just: ["a"] })
// :: identity a = a
const identity = (() => {
const map = fn.identity
const lift2 = fn.identity
const pure = fn.identity
const foldMap = _ => fn.identity
const traverse = _ => fn.identity
return { map, lift2, pure, foldMap, traverse }
})()
// :: compose f g a = f (g a)
const compose = f => g => {
const map = fn.compose(f.map)(g.map)
const lift2 = fn.compose(f.lift2)(g.lift2)
const pure = fn.compose(f.pure)(g.pure)
const foldMap = m => fn.compose(f.foldMap(m))(g.foldMap(m))
const { fold } = classes.foldable({ foldMap })
const traverse = a => fn.compose(f.traverse(a))(g.traverse(a))
const filter = fn.compose(f.map)(g.filter)
return { map, lift2, pure, foldMap, fold, traverse, filter }
}
// :: absurd a = ⊥
const absurd = (() => {
const is = _ => false
const absurd = _ => { throw "The impossible has happened, you're trying to evaluate a void value! Check your types!" }
const map = _ => absurd
return { map }
})()
// :: union f g a = f a | g a
const union = q => r => {
const is = x => q.is(x) || r.is(x)
const map = f => x => q.is(x) ? q.map(f)(x) : r.map(f)(x)
const foldMap = m => f => x => q.is(x) ? q.foldMap(m)(f)(x) : r.foldMap(m)(f)(x)
const { fold } = classes.foldable({ foldMap })
const filter = f => x => q.is(x) ? q.filter(f)(x) : r.filter(f)(x)
return { is, map, foldMap, fold, filter }
}
const undefinedOr = (() => {
const nope = undefined
const yup = x => x
const match = ({ nope, yup }) => x => x === undefined ? nope : yup(x)
const is = _ => true
const map = f => match({
nope,
yup: f
})
const foldMap = m => f => match({
nope: m.empty,
yup: f
})
const { fold } = classes.foldable({ foldMap })
const filter = f => match({
nope,
yup: x => maybe.match({ nothing: nope, just: yup })(f(x))
})
return { nope, yup, match, is, map, foldMap, fold, filter }
})()
const array = (() => {
const is = x => Array.isArray(x)
const map = f => xs => xs.map(f)
const foldMap = m => f => xs => xs.reduce((p, c) => m.append(p)(f(c)), m.empty)
const { fold } = classes.foldable({ foldMap })
const filter = f => xs => xs.reduce((p, c) => maybe.match({ nothing: p, just: x => [...p, c] })(f(c)), [])
return { is, map, foldMap, fold, filter }
})()
const prop = p => {
const is = x => Object.prototype.hasOwnProperty.call(x, p)
const map = f => o => ({ ...o, [p]: f(o[p]) })
const foldMap = _ => f => ({ [p]: x }) => f(x)
const { fold } = classes.foldable({ foldMap })
return { is, map, foldMap, fold }
}
const int = (() => {
const sum = { append: x => y => x + y, empty: 0 }
return { sum }
})()
const tuple = (() => {
const map = f => ([a, b]) => [a, f(b)]
const bifoldMap = m => f => g => ([a, b]) => m.append(f(a))(f(b))
const { lfoldMap, rfoldMap } = classes.bifoldable({ bifoldMap })
const foldMap = rfoldMap
const { fold } = classes.foldable({ foldMap })
return { map, lfoldMap, rfoldMap, foldMap, fold }
})()
// :: cofree f a = [a, f (cofree f a)]
const cofree = f => {
const tf = compose(tuple)(f)
const map = ab => cata(tf)(([a, b]) => [f(a), b])
const foldMap = m => am => cata(tf)(([a, fm]) => {
const m1 = am(a)
const m2 = f.fold(m)(fm)
return m.append(m1)(m2)
})
const { fold } = classes.foldable({ foldMap })
return { map, foldMap, fold }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment