Skip to content

Instantly share code, notes, and snippets.

@brosenan
Created March 3, 2017 14:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brosenan/dfa00a425fef06d3bed864d125256e24 to your computer and use it in GitHub Desktop.
Save brosenan/dfa00a425fef06d3bed864d125256e24 to your computer and use it in GitHub Desktop.
State Monad in Clojure
(ns foo)
(defn m-const [val]
(fn [state]
[state val]))
(defn m-do [& actions]
(if (= (count actions) 1)
(first actions)
; else
(fn [state]
(let [[state _] ((first actions) state)]
((apply m-do (rest actions)) state)))))
(defn m-set [key action]
(fn [state]
(let [[state val] (action state)]
[(assoc state key val)])))
(defn m-get [key]
(fn [state]
[state (get state key)]))
(defn m-map [monads]
(fn [state]
(loop [res nil
monads monads
state state]
(if (empty? monads)
[state (reverse res)]
; else
(let [[state val] ((first monads) state)]
(recur (cons val res) (rest monads) state))))))
(defn monadic [func]
(fn [& m-args]
(fn [state]
(let [[state args] ((m-map m-args) state)]
[state (apply func args)]))))
(defn m-if [test then else]
(fn [state]
(let [[state cond] (test state)]
(if cond
(then state)
(else state)))))
(let [test (m-do (m-set :foo (m-do (m-set :bar (m-const 3))
(m-const 4)))
(m-set :foo ((monadic +) (m-get :foo) (m-get :bar)))
(m-if ((monadic =) (m-get :foo) (m-const 7))
(m-const "Success")
; else
(m-const "Failure")))]
(test {}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment