Monad transformers

Monad transformers are type constructors that build monads parameterized by other monads.

class MonadTrans t where
    lift :: Monad m => m a -> t m a
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }

instance (Monad m) => Monad (StateT s m) where
    return a = StateT $ \s -> return (a, s)
    m >>= k  = StateT $ \s0 -> do          -- in monad m
                 ~(a, s1) <- runStateT m s0
                 runStateT (k a) s1

instance MonadTrans (StateT s) where
    lift ma = StateT $ \s -> do            -- in monad m
                a <- ma
                return (a, s)

get :: (Monad m) = > StateT s m s
put :: (Monad m) = > s -> StateT s m ()
import Control.Monad.Trans
import Control.Monad.Trans.State

main :: IO ()
main = runStateT go 0 >>= print
  where go = do xplusplus >>= lift . print
                xplusplus >>= lift . print
        xplusplus = do n <- get; put (n + 1); return n

*Main> main
0
1
((),2)

MonadIO

class (Monad m) => MonadIO m where
    liftIO :: IO a -> m a

instance MonadIO IO where
    liftIO = id
instance (MonadIO m) => MonadIO (StateT s m) where
    liftIO = lift . liftIO

myprint :: (Show a, MonadIO m) => a -> m ()
myprint a = liftIO $ print $ show a
oneTwo :: (Int, Int)
oneTwo = (fst y, snd x)
    where x = (1, snd y)    -- mutual recursion
          y = (fst x, 2)

nthFib :: Int -> Integer
nthFib n = fibList !! n
    where fibList = 1 : 1 : zipWith (+) fibList (tail fibList)
-- in standard library
fix :: (a -> a) -> a
fix f = let x = f x in x
-- now, we use it. We define (x, y) to be the fixed point of a carefully constructed function.
oneTwo ' :: (Int, Int)
oneTwo ' = (fst y, snd x)
  where (x, y) = fix $ \ ~(x0, y0) -> let x1 = (1, snd y0)
                                          y1 = (fst x0, 2)
                                          in (x1, y1)

nthFib ' n = fibList !! n
where fibList = fix $ \l -> 1 : 1 : zipWith (+) l (tail l)

The RecursiveDo extension

oneTwo'' :: (MonadFix m) => m (Int, Int)
oneTwo'' = do
  rec x <- return (1, snd y)
      y <- return (fst x, 2)
  return (fst y, snd x)
oneTwo''' :: (MonadFix m) => m (Int, Int)
oneTwo''' = do
  (x, y) <- mfix $ \ ~(x0, y0) -> do x1 <- return (1, snd y0)
                                     y1 <- return (fst x0, 2)
                                     return (x1, y1)
  return (fst y, snd x)

Example uses of mfix and rec

data Link a = Link !a !(MVar (Link a)) -- note ! is okay

mkCycle :: IO (MVar (Link Int))
mkCycle = do
  rec l1 <- newMVar $ Link 1 l2        -- but $! would diverge
      l2 <- newMVar $ Link 2 l1
  return l1
class MyClass t where
    myTypeName :: t -> String        -- non-strict in argument
    myDefaultValue :: t
instance MyClass Int where
    myTypeName _ = "Int"
    myDefaultValue = 0

getVal :: (MyClass t) => IO t
getVal = mfix $ \t -> do      -- doesn't use mfix's full power
  putStrLn $ "Caller wants type " ++ myTypeName t
  return myDefaultValue
newtype Identity a = Identity { runIdentity :: a }
instance Monad Identity where
    return = Identity
    m >>= k = k (runIdentity m)
--newtype compiles to nothing, so basically same as fix:
instance MonadFix Identity where
    mfix f = let x = f (runIdentity x) in x

fixIO, IO Monad fixed point

A generic mfix is not possible

MultiParamTypeClasses extension

FlexibleInstances extension

Overlapping Instances extension

This extension is used but also widely frowned upon

A case against OverlappingInstances

module Help where
    class MyShow a where
      myshow :: a -> String
    instance MyShow a => MyShow [a] where
      myshow xs = concatMap myshow xs

    showHelp :: MyShow a => [a] -> String
    showHelp xs = myshow xs     -- doesn't see overlapping instance

module Main where
    import Help

    data T = MkT
    instance MyShow T where
      myshow x = "Used generic instance"
    instance MyShow [T] where
      myshow xs = "Used more specific instance"

    main = do { print (myshow [MkT]); print (showHelp [MkT]) }
*Main> main
"Used more specific instance"
"Used generic instance"

Flexible contexts extension

toInt val = convert val :: Int
toInt :: (Convert a Int) => a -> Int

FunctionalDependencies extension

Undecidable vs. exponential -- who cares?

UndecidableInstances extension

Examples

Type-level booleans