Skip to content

Instantly share code, notes, and snippets.

@mvaldesdeleon
Created November 20, 2017 19:49
Show Gist options
  • Save mvaldesdeleon/5eabc44a781e5d7d04662e4958c38e1c to your computer and use it in GitHub Desktop.
Save mvaldesdeleon/5eabc44a781e5d7d04662e4958c38e1c to your computer and use it in GitHub Desktop.
State monad
function State(fn) {
this._fn = fn;
}
State.state = fn => new State(fn);
State.of = val => State.state(state => [val, state]);
State.get = State.state(state => [state, state]);
State.put = state => State.state(() => [undefined, state]);
State.modify = fn => State.state((state) => [undefined, fn(state)]);
State.prototype.evalState = function(state) {
return this.runState(state)[0];
};
State.prototype.execState = function(state) {
return this.runState(state)[1];
};
State.prototype.runState = function(state) {
return this._fn(state);
};
State.prototype.map = function(fn) {
return State.state(state => {
const [result, nextState] = this.runState(state);
return [fn(result), nextState];
});
};
State.prototype.ap = function(sval) {
return State.state(state => {
const [fn, nextState] = this.runState(state);
const [val, finalState] = sval.runState(nextState);
return [fn(val), finalState];
});
};
State.prototype.bind = function(fn) {
return State.state(state => {
const [result, nextState] = this.runState(state);
const [finalResult, finalState] = fn(result).runState(nextState);
return [finalResult, finalState];
});
};
State.prototype.join = function() {
return State.state(state => {
const [result, nextState] = this.runState(state);
const [finalResult, finalState] = result.runState(nextState);
return [finalResult, finalState];
});
};
/*
type LabelM = State Int
increment :: LabelM String
increment = state $ \i -> let j = i + 1
in ("$" ++ show j, j)
labels :: Bool -> LabelM [(String, String)]
labels discard = f <$> twoLabels
<*> twoLabels
<*> twoLabels
where f a b c = if discard
then [a, c]
else [a, b, c]
-- (,) <- is an operator creating a tuple
twoLabels :: LabelM (String, String)
twoLabels = (,) <$> increment <*> increment
main :: IO ()
main = do putStrLn "Enter `True`, or `False`"
discard <- getLine
print (evalState (labels . read $ discard) 0)
*/
const increment = State.state(i => [`\$${i + 1}`, i + 1]);
const labels = discard => {
const twoLabels = increment.map(a => b => [a, b]).ap(increment);
const f = a => b => c => discard ? [a, c] : [a, b, c];
return twoLabels.map(f).ap(twoLabels).ap(twoLabels);
};
const main = discard => {
console.log(labels(discard).evalState(0));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment