Created
December 18, 2015 20:43
-
-
Save blischalk/7bf08634d543ddd4b040 to your computer and use it in GitHub Desktop.
Monad Gist
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
;; Lets say you have a tight rope walker Pierre and he carries a pole | |
;; As birds land on the pole on one side or the other it gets | |
;; hard for the tight rope walker to keep his balance | |
;; If there is more than a 4 bird difference between the left | |
;; and right side of the pole he will fall off the tightrope | |
(def pole [0 0]) | |
(def threshold 4) | |
(defn abs [n] (max n (- n))) | |
(defn land-left [n [l r]] | |
(let [new-left (+ n l)] | |
(if (< (abs (- new-left r)) threshold) | |
[new-left r] | |
nil))) | |
(defn land-right [n [l r]] | |
(let [new-right (+ n r)] | |
(if (< (abs (- new-right l)) threshold) | |
[l new-right] | |
nil))) | |
;; This scenario will be ok because Pierre's pole is always within tolerence | |
(->> pole | |
(land-left 2) | |
(land-right 2) | |
(land-left 3) | |
(land-right 3)) ;; [5 5] | |
;; In this scenario what we want to happen is to just nicely return nil | |
;; letting us know that our friend Pierre has lost his balance and | |
;; tumbled. Alas that is not what will happen | |
(->> pole | |
(land-left 2) | |
(land-right 2) | |
(land-left 10) ;; BOOM! java.lang.NullPointerException | |
(land-right 3)) ;; Wanted to see nil here | |
;; Utilizing the Maybe Monad you would be able define a value in | |
;; a context of possible failure | |
;; Here we do our best with an extra nil check within our functions | |
(defn land-left' [n maybe] | |
(if (nil? maybe) nil | |
(let [[l r] maybe | |
new-left (+ n l)] | |
(if (< (abs (- new-left r)) threshold) | |
[new-left r] | |
nil)))) | |
(defn land-right' [n maybe] | |
(if (nil? maybe) nil | |
(let [[l r] maybe | |
new-right (+ n r)] | |
(if (< (abs (- new-right l)) threshold) | |
[l new-right] | |
nil)))) | |
(->> pole | |
(land-left' 2) | |
(land-right' 2) | |
(land-left' 10) ;; Works fine now | |
(land-right' 3)) ;; nil | |
;; With a type system and Monads the concept of a context of possible failure | |
;; can be encapsulated. Notice the below functions don't check for nil | |
;; Haskell example: | |
landLeft :: Birds -> Pole -> Maybe Pole | |
landLeft n (left,right) | |
| abs ((left + n) - right) < 4 = Just (left + n, right) | |
| otherwise = Nothing | |
landRight :: Birds -> Pole -> Maybe Pole | |
landRight n (left,right) | |
| abs (left - (right + n)) < 4 = Just (left, right + n) | |
| otherwise = Nothing | |
;; The below implemtation produces "Nothing" and does not throw an exception | |
return (0,0) >>= landLeft 1 >>= landRight 4 >>= landLeft (-1) >>= landRight (-2) | |
;; The bind operator >>= takes a value that is wrapped in a context (such as | |
;; the context of possible failure) and is implemented for the Maybe type | |
;; as such | |
instance Monad Maybe where | |
(Just x) >>= k = k x | |
Nothing >>= _ = Nothing | |
;; E.g if the context has a value in it return the result of applying the passed | |
;; in function to that value | |
;; Otherwise just return Nothing | |
;; Attempting a loose interpretation in Clojure | |
;; The bind operator here doesn't actually extract any value | |
;; out of a context but it does provide a similar functionality | |
(defn >>= [context f] | |
(if (nil? context) nil | |
(f context))) | |
(defn land-left'' [n pole] | |
(let [[l r] pole | |
new-left (+ n l)] | |
(if (< (abs (- new-left r)) threshold) | |
[new-left r] | |
nil))) | |
(defn land-right'' [n pole] | |
(let [[l r] pole | |
new-right (+ n r)] | |
(if (< (abs (- new-right l)) threshold) | |
[l new-right] | |
nil))) | |
(-> pole | |
(>>= (partial land-left'' 2)) | |
(>>= (partial land-right'' 2)) | |
(>>= (partial land-left'' 10)) | |
(>>= (partial land-right'' 3))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment