Skip to content

Instantly share code, notes, and snippets.

@sritchie
Created January 21, 2012 19:49
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sritchie/1653728 to your computer and use it in GitHub Desktop.
Save sritchie/1653728 to your computer and use it in GitHub Desktop.
(ns monad-explore.core
(:use clojure.algo.monads))
(defmacro let?
"Almost the same as let. If you add the :ensure keyword paired with
some predicate as a var in the let form, let? will not continue
unless the predicate evaluates to true. (The predicate will have
access to all bindings above.)"
[bindings & body]
(let [[bind [kwd pred & more]] (split-with (complement #{:ensure}) bindings)]
`(let [~@bind]
~@(cond (and kwd more) [`(when ~pred (let? [~@more] ~@body))]
kwd [`(when ~pred ~@body)]
:else body))))
(let? [a 2
:ensure (= a 2)
b (+ a 2)
:ensure (= b 3)]
(* a b))
;;=> nil
(let? [a 2
:ensure (= a 2)
b (+ a 2)
:ensure (= b 4)]
(* a b))
;;=> 8
;; I know it's the identity monad, I just wanted to get nil when guards failed vs. undefined.
(defmonad skip-m
[m-result identity
m-bind (fn [mv mf] (mf mv))
m-zero nil])
(domonad skip-m
[a 2
:when (= a 2)
b (+ a 2)
:when (= b 3)]
(* a b))
;;=> nil
(domonad skip-m
[a 2
:when (= a 2)
b (+ a 2)
:when (= b 4)]
(* a b))
;;=> 8
;; OR, without defining anything of my own at all....
(domonad maybe-m
[a 2
:when (= a 2)
b (+ a 2)
:when (= b 3)]
(* a b))
;;=> nil
(domonad maybe-m
[a 2
:when (= a 2)
b (+ a 2)
:when (= b 4)]
(* a b))
;;=> 8
@candera
Copy link

candera commented Jan 23, 2012

I think I might be blind: I can't see any difference between the form at line 16 and the form at line 23. I'm guessing that first b was supposed to be 3.

@sritchie
Copy link
Author

Whoops, you're absolutely right. That's what I get for not copy-pasting directly out of the repl. Thanks for the note, the gist should now be correct.

@khinsen
Copy link

khinsen commented Jan 23, 2012

You could use maybe-m instead of defining your own skip-m.

@jduey
Copy link

jduey commented Jan 23, 2012

Pretty cool how a little experience with monads leads to elegant code, isn't it.

@sritchie
Copy link
Author

@jduey, absolutely. I came back after leaving them alone for a few months and everything clicked.

@khinsen, nice. I don't know why I didn't assume that m-zero for maybe-m was nil.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment