import Data.Monoid
newtype Writer w a = Writer { runWriter :: (a, w) } deriving Show
instance Functor (Writer w) where
fmap f (Writer (a, w)) = Writer (f a, w)
instance Monoid w => Applicative (Writer w) where
pure a = Writer (a, mempty)
Writer (f, w) <*> Writer (a, w') = Writer (f a, w' <> w)
instance Monoid w => Monad (Writer w) where
return = pure
Writer (a, w) >>= f = let Writer (a', w') = f a
in Writer (a', w <> w')
tell :: w -> Writer w ()
tell w = Writer ((), w)
(>=>) :: Monoid w => (a -> Writer w b) -> (b -> Writer w c) -> (a -> Writer w c)
m1 >=> m2 = \x ->
let Writer (y, s1) = m1 x
Writer (z, s2) = m2 y
in Writer (z, s1 <> s2)
plus2, mult5, minus3 :: Int -> Writer String Int
plus2 i = Writer (i + 2, "Plus two\n")
mult5 i = Writer (i * 5, "Times five\n")
minus3 i = do
tell "Minus three\n"
return (i - 3)
main = print $ (mult5 >=> plus2 >=> minus3) 3