Incompatibilities between MTL 1 and MTL 2

From HaskellWiki
Revision as of 15:19, 6 February 2021 by Gwern (talk | contribs) (Reverted edits by Tomjaguarpaw (talk) to last revision by YitzGale)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Version 2 of the Monad Transformer Library introduced some small incompatibilities relative to version 1, described below. See "Upgrading from MTL 1 to MTL 2" for instructions on how to make code written for version 1 work with version 2.

The interface of mtl-2 is close to that of mtl-1, but with the following differences (illustrated with Reader):

  • Instances of Applicative and Alternative have been added as appropriate, e.g.
instance (Applicative m) => Applicative (ReaderT r m) where ...
instance (Alternative m) => Alternative (ReaderT r m) where ...

Rationale: These classes postdate the MTL, and such instances have been repeatedly defined in various packages. They belong together with the type constructors.

  • Functor instances for monad transformers no longer require Monad where Functor is sufficient. Unfortunately this is incompatible because Functor is not a superclass of Monad, e.g.
instance (Monad m) => Functor (ReaderT r m) where ...
is replaced by
instance (Functor m) => Functor (ReaderT r m) where ...

Rationale: These instances are more general, and are consistent with the instances of other classes.

  • Simple monads are now aliases for monad trasformers applied to Identity, e.g.
newtype Reader r a = Reader { runReader :: r -> a }
is replaced by
type Reader r = ReaderT r Identity
reader :: (r -> a) -> Reader r a
reader f = ReaderT (Identity . f)

runReader :: Reader r a -> r -> a
runReader m = runIdentity . runReaderT m

Rationale: This avoids repetition in the interfaces of both transformers and mtl-2. It makes transformers more useful on its own, and also saves clients of mtl from defining instances for both Reader r and ReaderT r and ensuring that they are consistent.

  • The instance Error String is restructured to avoid a type synonym instance:
instance Error String where
    noMsg  = ""
    strMsg = id
  is replaced by
instance ErrorList a => Error [a] where
    strMsg = listMsg
class ErrorList a where
    listMsg :: String -> [a]
instance ErrorList Char where
    listMsg = id

Rationale: This makes the instance Haskell 98, so it can be included in the transformers package.