views:

210

answers:

2

I've been reading an excellent introduction to monads for Clojure programmers. The article illustrates that the Identity monad is functionally equivalent to Clojure's let and that the Sequence/List monad is equivalent to for.

When the article gets to monad transformers, it shows an example combining the Maybe and Sequence monads. Ok, so one reason for using a Sequence monad instead of a for is that I can transform it. However, transforming an Identity monad doesn't make sense to me - wouldn't that always be equivalent to just building up whatever the transforming monad is? For example, if I transformed Maybe with Identity - doesn't that just give me a Maybe, which would have been easier to declare directly?

Can someone clear up whether there's a practical use in Clojure for choosing an Identity monad over a let (perhaps I'm not thinking all the way through the implications of transformers?), or is it just there for theoretical completeness?

+4  A: 

One good reason is that you can write monadic functions which are not tied to a particular monad and then execute them in a with-monad block. identity-m gives you the option of not involving any special monadic voodoo if you write (with-monad identity-m ...).

(Clearly, this won't work if your monadic function makes essential use of some properties of the monad its working with, like the availability of a getter and a setter for state etc. Not all monadic functions are like this, however.)

Michał Marczyk
+2  A: 

Indeed the identity monad is very useful as a base in a monad transformer. For instance the maybe monad transformer (maybe-t) allows for a nothing value other than nil:

1:2 => (use 'clojure.contrib.monads)
nil
1:3 => (domonad maybe-m [a 1 b 2] (+ a b))
3
1:4 => (domonad maybe-m [a 1 b nil] (+ a b))
nil
;; Domain uses the :fail keyword as the nil value:
1:6 => (domonad (maybe-t identity-m :fail) [a 1 b :fail] (+ a b))
:fail

Note that using maybe-m as the base monad would shortcut on both :fail and nil, instead of just :fail.

Gijs