2
votes

I've seen two sources that say the following is an identity monad. But I don't think that's true because it fails the Third Monad Law.

(defn result [v] (fn [] v))
(defn bind [mv f] (f (mv))

Fails the Third Monad Law

(bind (bind (result 3) identity) identity)

The inner bind call returns 3, which is not a monadic value, so Java returns the error of trying to call the function (3).

Am I missing something?

1

1 Answers

6
votes

The definitions of bind and result are fine, and do constitute a monad. However, identity is not a legal function to pass to bind for your monad. In Haskell, that would not pass the typechecker, because

bind :: (Monad m) => m a -> (a -> m b) -> m b

The second argument here is your f, in this case identity. But identity :: a -> a does not fit with the type required for bind's f.

In order to use something "identity-like" in your monad, you need to lift identity into the monad by composing it with result. For example,

(let [id (comp result identity)] ;; or (liftm identity), if you have liftm
  (bind (bind (result 3) id) id))

returns (result 3), ie (fn [] 3).

Edit

I did some more thinking about this, since my assertion that a -> a is an incompatible type with a -> m b is clearly not quite right: if you let a be m b, the types do match. So it's okay to use identity as the bind function in some cases. Specifically, if your original input is (result (result 3)), you can bind identity and get out just (result 3). In fact, (bind identity x) is basically (join x)! This is not exactly news - I've read it multiple times - but I guess it hadn't sunk in, or I'd have answered this question more correctly to begin with.

Anyway, just thought I'd share this, since it's a bit topical and should flesh out my answer a bit.