Monads usage

2013-04-08 Thread Carlos Galdino
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.




Re: Monads usage

2013-04-08 Thread Timothy Baldridge
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.comwrote:

 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

Re: Monads usage

2013-04-08 Thread Timothy Baldridge
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.comwrote:

 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.comwrote:

 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

Re: Monads usage

2013-04-08 Thread Armando Blancas
Last week I released a project with a monadic translator that needed to:
- work on sequences of expressions, arbitrarily nested
- generate Clojure code or stop and report the first error
- maintain a symbol table with easy access but not global state

The relevant code is here:
https://github.com/blancas/eisen/blob/master/src/main/clojure/blancas/eisen/trans.clj

The code uses a StateT monad transformer and Either monad wrapped in five 
API functions: -left, -right, get-se, modify-se, run-se. Functions report 
errors with (-left); function (-right) wraps good values. The macro 
(monad) corresponds to Haskell's do; it chains monadic values or 
short-circuits and propagates errors.


(defn trans-binop
  Translates the application of a binary operator.
  [ast]
  (monad [x (trans-expr (:left ast))
  y (trans-expr (:right ast))]
(let [f (- ast :op :value str symbol)]
  (-right `(~f ~x ~y)


The symbol table is available through get-se and modify-se. A typical use 
case is to enter declared names, translate the expressions, then remove the 
names from the symbol table.

(defn trans-let
  Translates a let expression.
  [{:keys [decls exprs]}]
  (let [env (map (comp symbol :name) decls)]
(monad [_ (modify-se into env)
decls (trans-bindings decls)
exprs (trans-exprs exprs)
_ (modify-se difference env)]
  (-right `(let [~@(apply concat decls)] ~@exprs)


To translate expressions in a sequence it uses the generic function (seqm); 
function (run-se) evaluates the resulting sequenced monads using an initial 
state predefs. The result from (run-se) feeds (either) which evaluates to 
the first form on -left and to the second on -right.

(let [job (monad [v (seqm (map eval-ast coll))] (-right v))]
(either [res (run-se job predefs)]
  {:ok false :error res}
  {:ok true :decls (map first res) :value (- res last second)})))


On Monday, April 8, 2013 7:56:35 AM UTC-7, Carlos Galdino 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.