oops, gen-plan was missing a helper function: (defn- with-bind [id expr psym body] `(fn [~psym] (let [[~id ~psym] ( ~expr ~psym)] (assert ~psym "Nil plan") ~body)))
On Mon, Apr 8, 2013 at 9:32 AM, Timothy Baldridge <tbaldri...@gmail.com>wrote: > 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) > -- “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.