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.


Reply via email to