{-# LANGUAGE FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, OverlappingInstances, UndecidableInstances #-}
module Main where

class (Monad m) => MonadIO m where
    -- | Lift a computation from the 'IO' monad.
    liftIO :: IO a -> m a

instance MonadIO IO where
    liftIO = id

class XMLGenerator m where
    genElement :: (Maybe String, String) -> m ()

newtype IdentityT m a = IdentityT { runIdentityT :: m a }
    deriving (Functor, Applicative, Monad, MonadIO)

instance (MonadIO m) => (XMLGenerator (IdentityT m)) where
    genElement _ = liftIO $ putStrLn "in genElement"

main :: IO ()
main =
    do runIdentityT web
       putStrLn "done."

class (Widgets x) => MonadRender x
class (XMLGenerator m)  => Widgets m
-- instance Widgets (IdentityT IO) -- if you uncomment this, it will work
instance (XMLGenerator m, MonadRender m) => Widgets m
instance MonadRender (IdentityT IO)

web :: ( MonadIO m
       , Widgets m
       , XMLGenerator m
       ) => m ()
web =
    do liftIO $ putStrLn "before"
       genElement (Nothing, "p")
       return ()
