I have a love/hate relationship with monads. I think their use in Clojure programming is much more limited than most would like to admit.
However, I have found a very nice use for them: in my case, I'm attempting to insert a very complex AST into Datomic. I'd like all my data to go into Datomic as one large transaction (a vector of hashmaps). My first attempt at this code looked like this: Assume my data is: {:type :+ :arg0 {:type :const :value 1} :arg1 {:type :const :value 2} Insert for the + node: (let [[arg0-id with-arg0] (insert-node (:arg0 this) plan) [arg1-id with-arg1] (insert-node (:arg1 this) with-arg1) [this-id with-this] (assert-entity {:arg0 arg0-id :arg1 arg1-od})] [this-id with-this]) So basically every single function has to return the last inserted id as well as a db tx plan that contains all items that need to be inserted. Not only is this code ugly, but I found it very error prone. Sometimes I would pass the wrong plan name in, and things would break. So I looked at this and said "why not use the state monad". So now insert-node looks like this: (insert-node [ent] (fn [plan] ..... do stuff ..... [ent plan])) I created a monad binding function called "gen-plan": (defmacro gen-plan [binds id-expr] (let [binds (partition 2 binds) psym (gensym "plan_") f (reduce (fn [acc [id expr]] `(~(with-bind id expr psym acc) ~psym)) `[~id-expr ~psym] (reverse binds))] `(fn [~psym] ~f))) And our example above looks like this: (gen-plan [arg0-id (insert-node (:arg0 this)) arg1-id (insert-node (:arg1 this)) this-id (assert-entity {:arg0 arg0-id :arg1 arg1-id})] this-id) Notice how the state monad makes the plan implicit. And now I can write super complex functions like this, without drowning in the code. Notice how this block (which generates a tx for writing a SSA style if expression to Datomic) is clear from any mentions of explicit state, but yet is remains completely functional. (gen-plan [fnc (get-in-plan [:state :fn]) test-id (write-ssa test) test-block (get-block) pre-then-block (add-block fnc) _ (set-block pre-then-block) then-val (write-ssa then) post-then-block (get-block) then-terminated? (terminated? post-then-block) pre-else-block (add-block fnc) _ (set-block pre-else-block) else-val (write-ssa else) post-else-block (get-block) else-terminated? (terminated? post-else-block) merge-block (add-block fnc) _ (set-block merge-block) phi-val (add-phi) _ (set-block test-block) br-id (terminate-block :inst.type/br test-id pre-then-block pre-else-block) _ (if then-terminated? (no-op) (gen-plan [_ (set-block post-then-block) _ (terminate-block :inst.type/jmp merge-block) _ (add-to-phi phi-val post-then-block then-val)] nil)) _ (if else-terminated? (no-op) (gen-plan [_ (set-block post-else-block) _ (terminate-block :inst.type/jmp merge-block) _ (add-to-phi phi-val post-else-block else-val)] nil)) _ (set-block merge-block)] phi-val) So I look at this way, I see monads as a purely academic exercise 90% of the time. To try to go "whole hog" and apply them to every problem at hand is just nonsense. However, there are times (like in this example) where monads end up being the perfect tool for the job at hand. So I say, instead of looking at a problem and saying "what monad is this?" Instead, look at ugly code and say "hrm...I wonder if programming method X could make this cleaner". If that method is a monad, awesome! Timothy On Mon, Apr 8, 2013 at 8:56 AM, Carlos Galdino <carloshsgald...@gmail.com>wrote: > Hi, > > I've been reading about monads for the past couple of weeks and I think I > got the idea, but I still don't know when to use it since I don't have > enough experience with functional programming. > > So, I'd like to ask you guys if you can point me to some examples of > Monads usage "in the wild". Because I've seen a lot of simple examples but > not a real one, used in a library, etc. > > Does anyone know a good example of real world usage? > > Thanks in advance. > > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- “One of the main causes of the fall of the Roman Empire was that–lacking zero–they had no way to indicate successful termination of their C programs.” (Robert Firth) -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.