Skip to content

Instantly share code, notes, and snippets.

@gabro
Last active November 21, 2016 13:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gabro/261f3e29805c782bc5c12e376a9ab8fa to your computer and use it in GitHub Desktop.
Save gabro/261f3e29805c782bc5c12e376a9ab8fa to your computer and use it in GitHub Desktop.
Applicative instances composition in vanilla js
function composeFunctor(f, g) {
function map(h, fga) {
return f.map(ga => g.map(h, ga), fga)
}
return { map }
}
function composeApplicative(f, g) {
const { map } = composeFunctor(f, g)
function ap(fgab, fga) {
return f.ap(f.map(h => ga => g.ap(h, ga), fgab), fga)
}
function of(a) {
return f.of(g.of(a))
}
return { map, ap, of }
}
// Example
// The Applicative instance for Array
const arr = {
map(f, fa) {
return fa.map(f)
},
of(a) {
return [a]
},
ap(fab, fa) {
return fab.reduce((acc, f) => acc.concat(fa.map(f)), [])
}
}
// The Applicative instance of Maybe
const maybe = {
map(f, fa) {
return fa == null ? null : f(fa)
},
of(a) {
return a;
},
ap(fab, fa) {
return fab == null ? null : this.map(fab, fa)
}
}
// Compose them!
const x = [" foo ", null, "bar "];
// x.map(v => v.trim()) // BOOM! Explodes on null
composeFunctor(arr, maybe).map(v => v.trim(), x) // ["foo", null, "bar"]
const f = v => v.trim()
const g = v => v.startsWith("b")
composeApplicative(arr, maybe).ap([f, g], x) // ["foo", null, "bar", "false", null, "true"]
@gabro
Copy link
Author

gabro commented Nov 21, 2016

Maybe is encoded very naively as a native js value. The "trick" is checking for null (or undefined) in its map function.

@lambdista
Copy link

Still, really nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment