Question

with mtl, deriving MonadState seems to get make state operations properly lifted:


:set -XGeneralizedNewtypeDeriving
import Control.Applicative (Applicative)
import Control.Monad.Trans ( MonadIO, liftIO )
import Control.Monad.State (MonadState, evalStateT, modify, StateT, gets)

data State = State { int:: Int }
newtype St a = St { unSt :: StateT State IO a } deriving (Functor, Applicative, Monad, MonadIO, MonadState State)

let testLift = gets int >> return () :: St ()

for transformers, there is no MonadState


:set -XGeneralizedNewtypeDeriving
import Control.Monad.Trans.State.Strict (runStateT, evalStateT, modify, StateT, gets)
import Control.Monad.IO.Class ( MonadIO, liftIO )
import Control.Applicative (Applicative)


data State = State { int:: Int }
newtype St a = St { unSt :: StateT State IO a } deriving (Functor, Applicative, Monad, MonadIO)


let testLift = gets int >> return () :: St ()
Couldn't match type `StateT State m0' with `St'
Expected type: St Int
  Actual type: StateT State m0 Int
In the return type of a call of `gets'
In the first argument of `(>>)', namely `gets int'
In the expression: gets int >> return () :: St ()

What am I supposed to be doing to make this work with transformers?

Was it helpful?

Solution

You're supposed to use mtl to make that work. mtl and transformers aren't really competitors -- mtl depends on transformers! It exists to to add classes like MonadState that use functional dependencies so they don't have to be part of the core (Haskell-98) type definitions. There's also a package (monads-tf) that uses type families instead, which is also compatible with transformers (but, really, you shouldn't use it).

Maybe I should be asking: Why are you "switching from mtl to transformers"?

OTHER TIPS

The MonadState instance is in package monads-tf or monads-fd, depending on whether you use type functions or functional dependences. I tried it with monads-tf (because that's the package I prefer), and GHC wasn't able to derive a MonadState instance for St, so you'll have to write one yourself.

{-# OPTIONS_GHC -package transformers -package monads-tf -hide-package mtl #-}
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}

import Control.Monad.Trans.State.Strict (runStateT, evalStateT, modify, StateT)
import Control.Monad.State.Class  -- MonadState class
import Control.Monad.IO.Class ( MonadIO, liftIO )
import Control.Applicative (Applicative)

data State = State { int:: Int }
newtype St a = St { unSt :: StateT State IO a } deriving (Functor, Applicative, Monad, MonadIO)

instance MonadState St where
  type StateType St = State
  get = St get
  put x = St (put x)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top