Skip to content

Instantly share code, notes, and snippets.

@DrBoolean
Created February 27, 2016 16:38
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save DrBoolean/3f5ac08a5bf1c4673757 to your computer and use it in GitHub Desktop.
Save DrBoolean/3f5ac08a5bf1c4673757 to your computer and use it in GitHub Desktop.
Free(er) Monads Pt2
const daggy = require('daggy')
const Task = require('data.task')
const _ = require('lodash')
const kleisli_comp = (f, g) => x => f(x).chain(g)
const compose = (f, g) => x => f(g(x))
const id = x => x
//=============FREE=============
const Free = daggy.taggedSum({Impure: ['x', 'f'], Pure: ['x']})
const {Impure, Pure} = Free
Free.of = Pure
Free.prototype.map = function(f) {
return this.chain(a => Free.of(f(a)))
}
Free.prototype.chain = function(f) {
return this.cata({
Impure: (x, g) => Impure(x, kleisli_comp(g, f)),
Pure: x => f(x)
})
}
Free.prototype.foldMap = function(interpreter, of) {
return this.cata({
Pure: a => of(a),
Impure: (intruction_of_arg, next) =>
interpreter(intruction_of_arg).chain(result =>
next(result).foldMap(interpreter, of))
})
}
const liftF = command => Impure(command, Pure)
//=============IO via FREE=============
const IO = daggy.taggedSum({IO: ['f']})
const io = compose(liftF, IO.IO)
//=============Maybe via FREE=============
const Maybe = daggy.taggedSum({ Just: ['x'], Nothing: [] })
const {Just, Nothing} = Maybe
const just = compose(liftF, Just)
const nothing = liftF(Nothing)
//=============Examples=============
const data = {user: {name: 'jerry'}}
const safeProp = (k, o) => o[k] ? just(o[k]) : nothing
const localStorage = io(() => data)
const printLn = x => io(() => console.log(x))
const maybeToTask = m => m.cata({Just: Task.of, Nothing: Task.rejected})
const ioToTask = i => new Task((rej, res) => res(i.f()))
const maybe_name = safeProp('user', data)
.chain(u => safeProp('name', u))
.map(n => n.toUpperCase())
maybe_name.foldMap(maybeToTask, Task.of).fork(console.error, console.log)
// JERRY
const i = localStorage
.map(l => l.user)
.chain(printLn)
i.foldMap(ioToTask, Task.of).fork(console.error, id)
// {name: 'jerry'}
const dispatch = pairs =>
instruction_of_arg => {
const interpreter = _.find(pairs, ([type, inter]) =>
instruction_of_arg.constructor === type)[1]
return interpreter(instruction_of_arg)
}
const interpret = dispatch([[IO, ioToTask],
[Maybe, maybeToTask]])
const printName = localStorage
.chain(ls => safeProp('user', ls))
.chain(u => safeProp('name', u))
.map(n => n.toUpperCase())
.chain(printLn)
printName.foldMap(interpret, Task.of).fork(console.error, id)
// JERRY
@DrBoolean
Copy link
Author

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