import Control.Applicative data MyCoolIO a = MCIO (IO a) instance Functor MyCoolIO where fmap f (MCIO xIO) = MCIO $ fmap f xIO instance Applicative MyCoolIO where pure = MCIO . pure (MCIO fIO) <*> (MCIO xIO) = MCIO $ fIO <*> xIO instance Monad MyCoolIO where return = pure (MCIO xIO) >>= f = MCIO $ xIO >>= \x -> (let (MCIO r) = f x in r) (MCIO xIO) >> (MCIO yIO) = MCIO $ yIO >>= \y -> (xIO >> return y) myPutStrLn :: String -> MyCoolIO () myPutStrLn s = MCIO $ putStrLn s myMain :: MyCoolIO () -> IO () myMain (MCIO io) = io main = myMain $ do myPutStrLn "first" myPutStrLn "second" myPutStrLn "third"