I am trying to nest writer monad twice using Monad Transformers. Here is a sketch:
import Control.Monad.Identity
import Control.Monad.Writer
data Struct = S Bool
instance Monoid Struct where
mempty = S True
mappend (S a) (S b) = S (a && b)
data Collision = C Bool
instance Monoid Collision where
mempty = C False
mappend (C a) (C b) = C (a || b)
type CSInt = WriterT Collision (WriterT Struct Identity) Int
foo :: Int -> CSInt
foo x = do (tell (S False)) ; return x
The foo function does not compile, as I need to use tell on Struct monad, not Collision. Is it possible at all?
Having multiple similar layers is in fact one case where the mtl approach, which is meant to make lift implicit, has trouble as you mentionned. So you can use lift explicitly.
lift :: Writer Struct Bool -> WriterT Collision (Writer Struct) Bool
Thus
foo x = do lift (tell (S False)) ; return x