Skip to content

Instantly share code, notes, and snippets.

@mattfenwick
Created April 1, 2013 15:45
Show Gist options
  • Select an option

  • Save mattfenwick/5285683 to your computer and use it in GitHub Desktop.

Select an option

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.
(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