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 <[email protected]>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
> <[email protected]>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 [email protected]
>> Note that posts from new members are moderated - please be patient with
>> your first post.
>> To unsubscribe from this group, send email to
>> [email protected]
>> 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 [email protected].
>> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/groups/opt_out.