Created
March 3, 2017 14:50
-
-
Save brosenan/dfa00a425fef06d3bed864d125256e24 to your computer and use it in GitHub Desktop.
State Monad in Clojure
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
(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