{-# OPTIONS -fglasgow-exts #-} -- identity monad newtype Identity a = Identity {runIdentity :: a} instance Monad Identity where return = Identity Identity a >>= f = f a -- somewhat contrived example: processor class (Monad m) => IsItem m i where processItem :: i -> m () class (Monad m) => IsProcessor p m | m -> p where process :: (IsItem m i) => i -> m () -- ...some more methods, possibly involving p... -- canonical item type newtype Item m = Item {processItemImpl :: m ()} instance (Monad m) => IsItem m (Item m) where processItem = processItemImpl toItem :: (IsItem m i) => i -> Item m toItem = Item . processItem -- processor monad transformer newtype ProcessorT p m a = ProcessorT {runProcessorT :: m a} instance (Monad m) => Monad (ProcessorT p m) where return = ProcessorT . return ProcessorT m >>= f = ProcessorT (m >>= runProcessorT . f) instance (Monad m) => IsProcessor p (ProcessorT p m) where process = processItem -- processor monad newtype Processor p a = Processor {unwrap :: ProcessorT p Identity a} runProcessor :: Processor p a -> a runProcessor = runIdentity . runProcessorT . unwrap instance Monad (Processor p) where return = Processor . return Processor m >>= f = Processor (m >>= unwrap . f) castItem :: (IsItem (Processor p) i) => i -> Item (ProcessorT p Identity) castItem = Item . unwrap . processItem instance IsProcessor p (Processor p) where process = Processor . process . castItem