Last active
June 29, 2016 08:04
-
-
Save trygvea/0d5bc725242f6e956821be8ab8cc0078 to your computer and use it in GitHub Desktop.
Pure stateful computations in Javascript (ES6)
This file contains 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
// push & pop as pure stateful computations | |
const push = elem => stack => [null, [elem, ...stack]] | |
const pop = ([head, ...tail]) => [head, tail] | |
// ---------------------------------------------------------- | |
// Let's do a simple stack manipulation popping the first two | |
// elements and pushing their product back on to the stack. | |
// The boring way to do it: Note how we manually must lift | |
// the stack through computations. | |
// (compare that to stackManipM below) | |
const stackManip = stack => { | |
const [first, stack1] = pop(stack) | |
const [second, stack2] = pop(stack1) | |
return push(first*second)(stack2) | |
} | |
console.log("stackManip:");console.log(stackManip([3,2,1])) | |
// ---------------------------------------------------------- | |
// The monadic way. First define two helper functions | |
// Decorate a pure stateful computation with a flatMap | |
const statefulComputation = u => { | |
const h = (...args) => u(...args) | |
h.flatMap = f => statefulComputation ( s => { | |
const [a, newState] = h(s) | |
const g = f(a) | |
return g(newState) | |
}) | |
return h | |
} | |
// A haskell simulation of do (or scala for comprehension). | |
// Here, we traverse the computations (or any other monad) | |
// step by step from the js function * generator, combining | |
// steps with flatMap. | |
// Taken from https://curiosity-driven.org/monads-in-javascript | |
const doM = steps => { | |
const nextStep = value => { | |
const { done, value: nextValue } = steps.next(value) | |
return done ? nextValue : nextValue.flatMap(nextStep) | |
} | |
return nextStep() | |
} | |
// Define monadic versions of push & pop | |
const pushM = elem => statefulComputation(push(elem)) | |
const popM = statefulComputation(pop) | |
// ---------------------------------------------------------- | |
// And now, the monadic variant of stackManip: | |
// Note no references to stack in implementation! | |
// (compare to stackManip above) | |
const stackManipM = stack => doM(function*() { | |
const first = yield popM | |
const second = yield popM | |
return pushM(first * second) | |
}())(stack) | |
console.log("stackManipM:");console.log(stackManipM([3,2,1])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment