Sat Sep 1 09:20:21 EDT 2018

Monad transformers

EDIT: See bottom.  This is all a misunderstanding.

How to create a monad transformer?  E.g. instead of using one of the
standard ones directly, what about abstracting away an effect and
wrapping it only as part of a stack?


Trying to abstract the assembler as a monad transformer.  

-- Assembler.
data Asm i m t = Asm [i] (m t) -- deriving (Functor, Applicative)

instance Functor m => Functor (Asm i m) where
  fmap f (Asm is mv) = Asm is $ fmap f mv
instance Applicative m => Applicative (Asm i m) where
  pure v = Asm [] $ pure v
  (Asm is mf) <*> (Asm is' mv) = undefined
instance Monad m => Monad (Asm i m) where
  (Asm is' mv) >>= f = undefined

Stuck at <*>.  I don't understand how is and is' are supposed to be

This is essentially a writer monad, so it seems that it should just be
concatenation.  I see that algebraically, but not intuitively.

I think I can't do this in a day of mental fog.  Yeah brain is just
not starting up today..

EDIT: Tried again, I just can't juggle it.  It seems the value is
inside the inner monad, and somehow i need to get it out.  Some
knot-tying intuition missing?

Monads do not compose in general.  So it is to be expected that some
trickery goes into the implementation of bind of a monad transformer.

"Each Monad Transformer exists because monads do not compose in general."


Maybe what I'm trying to do is to create a generic way of composing?

this just has wrappers?

Let's have a look at the WriterT source.

So... the implementation is not what I expected: it uses runWriterT
internally.  So indeed: each monad transformer has some kind of trick.

instance (Monoid w, Monad m) => Monad (WriterT w m) where
#if !(MIN_VERSION_base(4,8,0))
    return a = writer (a, mempty)
    {-# INLINE return #-}
    m >>= k  = WriterT $ do
        ~(a, w)  <- runWriterT m
        ~(b, w') <- runWriterT (k a)
        return (b, w `mappend` w')
    {-# INLINE (>>=) #-}
    fail msg = WriterT $ fail msg
    {-# INLINE fail #-}

And... my definition is wrong!

newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }

The monoid value is inside the monad.