Fri Aug 14 17:39:49 EDT 2015

Conditional join?

For monad m, is there a way to write a class that has these two

maybeJoin :: m (m t) -> m t
maybeJoin :: m t     -> m t

I can't get this to work because the second pattern also matches the
first one, and also other type unification issues I don't understand.

This arises in a DSL with operations like:

   add :: t -> t -> m t

Where I would like to use nested expressions as well by defining
"evaluation order" on functions with signatures:

    t -> m t -> m t
  m t ->   t -> m t
  m t -> m t -> m t

I want it to pick the right one automatically.

It's easy to define the last one

   add' a b = join $ liftM2 f a b

And then insert return whenever needed.

Maybe look for "join $ liftM2" which seems to be an indicator of this
kind of problem popping up elsewhere..

Alternatively, use m t -> m t -> m t for everything, but replace bind

  a <= ...

expanding to:

  a' <- ...
  let a = return a'

This way it is guaranteed that the monadic operation has executed,
e.g. if a is used multiple times, the computation that produced a'
only ran once.

... >>= $ \x ->
... >>= $ \y ->
return ...

Could change that to >>>= where

(>>>=) :: Monad m => m a -> (m a -> m b) -> m b
m >>>= f = m >>= (f . return)