Created
April 1, 2013 15:45
-
-
Save mattfenwick/5285683 to your computer and use it in GitHub Desktop.
Simple example of error monad in Clojure. Shows how monads -- which can be pure functions, in the non-side-effecting sense -- can help reduce tedious, boilerplate code.
This file contains hidden or 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 whatever.core) | |
| (defn success | |
| "create a successful monadic value" | |
| [value] | |
| {:status "success" :value value}) | |
| (defn failure | |
| "create a failing monadic value" | |
| [value] | |
| {:status "failure" :value value}) | |
| (defn bind | |
| "takes a monadic value, and a function producing another monadic value. | |
| failures will short-circuit" | |
| [val f] | |
| (if (= "success" (val :status)) | |
| (f (val :value)) | |
| val)) | |
| (defn lookup | |
| "check whether a map contains a key, and if it does, return a success wrapper around the value. | |
| if the map doesn't have the key, return a failure with a relevant error message" | |
| [key map] | |
| (if (contains? map key) | |
| (success (map key)) | |
| (failure (str "couldn't find key " key)))) | |
| (defn xyz-bad | |
| "checks whether all 3 of the keys :x, :y, :z are in the map. | |
| fails if any are missing. doesn't report which key was missing on failure" | |
| [map] | |
| (if (and (contains? map :x) | |
| (contains? map :y) | |
| (contains? map :z)) | |
| (success [(map :x) (map :y) (map :z)]) | |
| (failure "couldn't find key"))) ;; <-- which key was missing? | |
| (defn xyz | |
| "same as xyz-bad, but also reports which key was missing on failure" | |
| [map] | |
| (if (contains? map :x) | |
| (if (contains? map :y) | |
| (if (contains? map :z) | |
| (success [(map :x) (map :y) (map :z)]) | |
| (failure "couldn't find key :z")) | |
| (failure "couldn't find key :y")) | |
| (failure "couldn't find key :x"))) | |
| (defn xyz-bind | |
| "monadic version of xyz. correctly reports missing keys" | |
| [map] | |
| (bind (lookup :x map) | |
| (fn [x] (bind (lookup :y map) | |
| (fn [y] (bind (lookup :z map) | |
| (fn [z] ["result: " x y z]))))))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment