data InterpreterM a = ExeInterpreter a | PropInterpreter a
newtype InterpreterMT m a = InterpreterMT { runInterpreterMT :: m (InterpreterM a) }
type Interpreter = InterpreterMT (StateT Int (ReaderT Int (ErrorT String IO)))
data Stmts = Statements Stmt Stmts | EmptyStmts
instance (Monad m) => Monad (InterpreterMT m) where
return x = InterpreterMT $ return (ExeInterpreter x)
x >>= f = InterpreterMT $ do
m <- runInterpreterMT x
case m of
(ExeInterpreter a) -> runInterpreterMT (f a)
interpreter :: Stmts -> Interpreter ()
interpreter EmptyStmts = return ()
interpreter (Statements s stmts) = lift $ local (\x -> x) (interpreter stmts)
instance MonadTrans InterpreterMT where
lift m = InterpreterMT $ do
x <- m
return $ ExeInterpreter x
Compiler gives me erorr in last line:
Couldn't match type `InterpreterMT
(StateT Int (ReaderT Int (ErrorT String IO)))'
with `StateT Int (ReaderT Int (ErrorT String IO))'
Expected type: Interpreter ()
Actual type: InterpreterMT
(InterpreterMT (StateT Int (ReaderT Int (ErrorT String IO)))) ()
In the expression: lift $ local (\ x -> x) (interpreter stmts)
In an equation for `interpreter':
interpreter (Statements s stmts)
= lift $ local (\ x -> x) (interpreter stmts)
How to repair it and why it is an error?
Okay, two problems.
First, lift has the following signature:
lift :: (MonadTrans t, Monad m) => m a -> t m a
So you have to supply non-transformed monadic action to lift. In other words, you can't use InterpreterMT in an argument to lift.
So you would need to unwrap it:
lift $ local id $ runInterpreterMT $ interpreter stmts
But now your return types don't make sense: runInterpreterMT $ ... has type
StateT Int (ReaderT Int (ErrorT String IO)) (InterpreterM ())
or, shortening transformer stack to M,
M (InterpreterM ())
while interpreter returns Interpreter (), which is
InterpreterMT (StateT Int (ReaderT Int (ErrorT String IO))) ()
or, shortening transformer stack,
InterpreterMT M ()
going back to type of lift, m a -> t m a becomes M (InterpreterM ()) -> InterpreterMT M (InterpreterM ()). (InterpreterM ()) is not ().
The root of the problem? Your InterpreterMT is not actually a monad transformer, since it doesn't really transform the monad. It transforms the value.
Easy fix? Provided that you can figure out a reasonable Monad instance for InterpreterMT (one you provided is doubtful), you can define a MonadReader instance for InterpreterMT:
instance MonadReader r m => MonadReader r (InterpreterMT m) where
local f = InterpreterMT . local f . runInterpreterMT
...
(you'll need UndecideableInstances for this particular definition)
General pattern seems to be
inInterpreter f = InterpreterMT . f . runInterpreterMT
Note that this is not a Functor.
Not sure what you want to achieve here, but this whole design seems... underdeveloped. Maybe it's a good idea to go back to drawing board and figure out what exactly you want your architecture to be like.
Related
In https://en.wikibooks.org/wiki/Haskell/Monad_transformers, I see
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
and then the instanciation of MaybeT as a monad:
instance Monad m => Monad (MaybeT m) where
return = MaybeT . return . Just
-- The signature of (>>=), specialized to MaybeT m:
-- (>>=) :: MaybeT m a -> (a -> MaybeT m b) -> MaybeT m b
x >>= f = MaybeT $ do maybe_value <- runMaybeT x
case maybe_value of
Nothing -> return Nothing
Just value -> runMaybeT $ f value
I do not understand the arg x in runMaybeT x. Shouldn't runMaybeT take an arg corresponding to a? But instead it is given x which is the entire MonadT monad
It's just standard record syntax. In a type definition such as
data Foo = Foo { a :: Int, b :: String }
it presumably does not surprise you that we automatically get functions a :: Foo -> Int and b :: Foo -> String.
It's absolutely no different for MaybeT. (It does use newtype rather than data but that doesn't matter here, the same would be true if the definition used data instead)
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
this gives us a function runMaybeT :: MaybeT m a -> m (Maybe a) for exactly the same reason that we get the functions a and b in the simpler example above. It's just what record syntax does.
Specifically in this case, as always with a newtype defined using record syntax, the runMaybeT function allows us to "unwrap" a monadic value, going from the abstract MaybeT m a to the more "concrete" representation as a value of type m (Maybe a).
This is used in the implementation of >>= for MaybeT m: since its first argument (x in your snippet) is of type MaybeT m a, we first need runMaybeT to get the "unwrapped" value of type m (Maybe a), then use the >>= of the "base monad" m (shown here with do notation) to "extract" a value of type Maybe a which is then pattern matched on in the usual way.
runMaybeT is a getter. It is a function that takes a MaybeT m a object, and returns an m (Maybe a) object, so it has signature MaybeT m a -> m (Maybe a).
Perhaps it is easier to understand however if we unpack the value with a pattern:
instance Monad m => Monad (MaybeT m) where
return = MaybeT . return . Just
MaybeT rm >>= f = MaybeT $ do
maybe_value <- rm
case maybe_value of
Nothing -> return Nothing
Just value -> runMaybeT $ f value
I am trying to pass a function in a Reader that is to be called from the same monad as the calling function, but I get an infinite type error.
The simplified code is:
{-# LANGUAGE FlexibleContexts #-}
module G2 where
import Control.Monad
import Control.Monad.Reader
data Foo m = Foo { bar :: m () }
runFoo :: MonadReader (Foo m) m => m ()
runFoo = do
b <- asks bar
b
main :: Monad m => m ()
main = do
let bar = return () :: m ()
foo = Foo bar
runReaderT runFoo foo
And the error is:
• Occurs check: cannot construct the infinite type:
m0 ~ ReaderT (Foo m0) m
arising from a functional dependency between:
constraint ‘MonadReader
(Foo (ReaderT (Foo m0) m)) (ReaderT (Foo m0) m)’
arising from a use of ‘runFoo’
instance ‘MonadReader r (ReaderT r m1)’ at <no location info>
• In the first argument of ‘runReaderT’, namely ‘runFoo’
In a stmt of a 'do' block: runReaderT runFoo foo
In the expression:
do let bar = ...
foo = Foo bar
runReaderT runFoo foo
• Relevant bindings include main :: m () (bound at G2.hs:16:1)
|
19 | runReaderT runFoo foo
| ^^
Any help would be much appreciated, thanks!
runFoo :: MonadReader (Foo m) m => m ()
Let's forget about the class, and just assume that MonadReader env mon means that mon ~ ((->) env). This corresponds to simply using (->) as our monad instead of the fancier ReaderT. Then you get m ~ ((->) m) => m (). You see that m needs to contain itself (specifically, the argument to m is m). This is OK for values, but it would be quite bad if the typechecker had to deal with infinitely large types. The same is true for ReaderT (and you need to use ReaderT because you call runReaderT runFoo). You need to define another newtype to encode this recursion:
data RecReader c a = RecReader { runRecReader :: c (RecReader c) -> a }
instance Functor (RecReader c) where
fmap f (RecReader r) = RecReader $ f . r
instance Applicative (RecReader c) where
pure = RecReader . const
RecReader f <*> RecReader g = RecReader $ \e -> f e (g e)
instance Monad (RecReader c) where
return = pure
RecReader x >>= f = RecReader $ \e -> runRecReader (f (x e)) e
instance MonadReader (c (RecReader c)) (RecReader c) where
ask = RecReader id
local f (RecReader x) = RecReader $ x . f
And it works:
runRecReader runFoo (Foo $ return ())
-- ==>
()
data InterpreterM a = ExeInterpreter a | PropInterpreter a
newtype InterpreterMT m a = InterpreterMT { runInterpreterMT :: m (InterpreterM a) }
instance (Monad m) => Monad (InterpreterMT m) where
return x = lift . return
x >>= f = InterpreterMT $ do
m <- runInterpreterMT x
case m of
(ExeInterpreter a) -> runInterpreterMT (f a)
instance MonadTrans InterpreterMT where
lift m = lift . (ExeInterpreter m)
I've got error, and I don't know why:
Interpreter.hs:25:20:
Couldn't match expected type `InterpreterMT m a'
with actual type `a2 -> t1 m1 a2'
In the expression: lift . return
In an equation for `return': return x = lift . return
In the instance declaration for `Monad (InterpreterMT m)'
Interpreter.hs:32:18:
Couldn't match expected type `InterpreterMT m a'
with actual type `a0 -> t0 m0 a1'
In the expression: lift . (ExeInterpreter m)
In an equation for `lift': lift m = lift . (ExeInterpreter m)
In the instance declaration for `MonadTrans InterpreterMT'
Interpreter.hs:32:27:
Couldn't match expected type `a0 -> m0 a1'
with actual type `InterpreterM (m a)'
In the return type of a call of `ExeInterpreter'
Probable cause: `ExeInterpreter' is applied to too many arguments
In the second argument of `(.)', namely `(ExeInterpreter m)'
In the expression: lift . (ExeInterpreter m)
What nicolas said. I didn't use the point-free style, so it might be a little bit easier to understand the types. You can look into example implementations to get a better feeling for transformers - Control.Monad.Trans.Class
data InterpreterM a = ExeInterpreter a
| PropInterpreter a
newtype InterpreterMT m a = InterpreterMT { runInterpreterMT :: m (InterpreterM a) }
instance (Monad m) => Monad (InterpreterMT m) where
-- return :: Monad m => a -> InterpreterMT m a
return x = InterpreterMT $ (return . ExeInterpreter) x
-- or after you defined MonadTrans below
-- return x = lift . return $ x
-- (>>=) :: Monad m => InterpreterMT m a -> (a -> InterpreterMT m b) -> InterpreterMT m b
(>>=) ima f = InterpreterMT $ do
ia <- runInterpreterMT ima
case ia of
(ExeInterpreter a) -> runInterpreterMT $ f a
(PropInterpreter a) -> runInterpreterMT $ f a
instance MonadTrans InterpreterMT where
-- lift :: Monad m => m a -> InterpreterMT m a
lift ma = InterpreterMT $ (return . ExeInterpreter) =<< ma
You dont seem to have any instance of MonadTrans in context so lift does not exist.
But more importantly, look at the type of the functions.
x is a value of type a and return x needs to give an element of type (InterpreterMT m) a.
For this you need to use the data constructor InterpreterMT and give it a m (InterpreterM a)
which means the body of return should be like
return . PropInterpreter $ x
I am trying to implement:
instance MonadTrans MaybeT where
lift m = m >>= \a -> MaybeT $ return (Just a)
And it gets compiler error:
Could not deduce (m ~ MaybeT m)
from the context (Monad m)
bound by the type signature for
lift :: Monad m => m a -> MaybeT m a
at MaybeTrans.hs:16:9-53
`m' is a rigid type variable bound by
the type signature for lift :: Monad m => m a -> MaybeT m a
Expected type: MaybeT m a
Actual type: m a
In the first argument of `(>>=)', namely `m'
In the expression: m >>= \ a -> MaybeT $ return (Just a)
In an equation for `lift':
lift m = m >>= \ a -> MaybeT $ return (Just a)
I cannot understand where I made a mistake.
Please help me ;)
If you specialise the type of lift to your MaybeT type you have:
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
lift :: Monad m => m a -> MaybeT m a
The type of >>= is Monad m => m a -> (a -> m b) -> m b so in your implementation:
lift m = m >>= \a -> MaybeT $ return (Just a)
you need to return a value of type m b while you return a value of type MaybeT m b, hence the error.
You now have two problems. The first is you need to move the application of MaybeT outside the application of >>=. The second is you need to construct a value of m (Maybe a) from the lamba passed to >>= i.e.
lift x = MaybeT $ x >>= \a -> return (Just a)
or simply:
lift x = MaybeT $ fmap Just x
Suppose I have a state monad such as:
data Registers = Reg {...}
data ST = ST {registers :: Registers,
memory :: Array Int Int}
newtype Op a = Op {runOp :: ST -> (ST, a)}
instance Monad Op where
return a = Op $ \st -> (st, a)
(>>=) stf f = Op $ \st -> let (st1, a1) = runOp stf st
(st2, a2) = runOp (f a1) st1
in (st2, a2)
with functions like
getState :: (ST -> a) -> Op a
getState g = Op (\st -> (st, g st)
updState :: (ST -> ST) -> Op ()
updState g = Op (\st -> (g st, ()))
and so forth. I want to combine various operations in this monad with IO actions. So I could either write an evaluation loop in which operations in this monad were performed and an IO action is executed with the result, or, I think, I should be able to do something like the following:
newtype Op a = Op {runOp :: ST -> IO (ST, a)}
Printing functions would have type Op () and other functions would have type Op a, e.g., I could read a character from the terminal using a function of type IO Char. However, I'm not sure what such a function would look like, since e.g., the following is not valid.
runOp (do x <- getLine; setMem 10 ... (read x :: Int) ... ) st
since getLine has type IO Char, but this expression would have type Op Char. In outline, how would I do this?
Use liftIO
You're already very close! Your suggestion
newtype Op a = Op {runOp :: ST -> IO (ST, a)}
is excellent and the way to go.
To be able to execute getLine in an Op context, you need to 'lift' the IO operation into the Op monad. You can do this by writing a function liftIO:
liftIO :: IO a -> Op a
liftIO io = Op $ \st -> do
x <- io
return (st, x)
You can now write:
runOp (do x <- liftIO getLine; ...
Use class MonadIO
Now the pattern of lifting an IO action into a custom monad is so common that there is a standard type class for it:
import Control.Monad.Trans
class Monad m => MonadIO m where
liftIO :: IO a -> m a
So that your version of liftIO becomes an instance of MonadIO instead:
instance MonadIO Op where
liftIO = ...
Use StateT
You've currently written your own version of the state monad, specialised to state ST. Why don't you use the standard state monad? It saves you from having to write your own Monad instance, which is always the same for the state monad.
type Op = StateT ST IO
StateT already has a Monad instance and a MonadIO instance, so you can use those immediately.
Monad transformers
StateT is a so-called monad transformer. You only want IO actions in your Op monad, so I've already specialized it with the IO monad for you (see the definition of type Op). But monad transformers allow you to stack arbitrary monads. This what intoverflow is talking about. You can read more about them here and here.
The basic approach would be to rewrite your Op monad as a monad transformer. This would allow you to use it in a "stack" of monads, the bottom of which might be IO.
Here's an example of what that might look like:
import Data.Array
import Control.Monad.Trans
data Registers = Reg { foo :: Int }
data ST = ST {registers :: Registers,
memory :: Array Int Int}
newtype Op m a = Op {runOp :: ST -> m (ST, a)}
instance Monad m => Monad (Op m) where
return a = Op $ \st -> return (st, a)
(>>=) stf f = Op $ \st -> do (st1, a1) <- runOp stf st
(st2, a2) <- runOp (f a1) st1
return (st2, a2)
instance MonadTrans Op where
lift m = Op $ \st -> do a <- m
return (st, a)
getState :: Monad m => (ST -> a) -> Op m a
getState g = Op $ \st -> return (st, g st)
updState :: Monad m => (ST -> ST) -> Op m ()
updState g = Op $ \st -> return (g st, ())
testOpIO :: Op IO String
testOpIO = do x <- lift getLine
return x
test = runOp testOpIO
The key things to observe:
The use of the MonadTrans class
The use of the lift function acting on getLine, which is used to bring the getline function from the IO monad and into the Op IO monad.
Incidentally, if you don't want the IO monad to always be present, you can replace it with the Identity monad in Control.Monad.Identity. The Op Identity monad behaves exactly the same as your original Op monad.