I am using the Hoopl library and would like to carry some state around while rewriting. The rewrite functions are polymorphic regarding the monad used, but I cannot figure out how to combine a State
monad with one of the library's Fuel
monads.
Below is a minimal example. MyMonad
is a synonym combining Hoopl's CheckingFuelMonad
and a State
monad carrying a flag. Stmt
is just a placeholder for my intermediate language and isn't really important.
{-# LANGUAGE GADTs, RankNTypes #-}
import Compiler.Hoopl
import Control.Monad.State
type MyMonad = CheckingFuelMonad (State Bool)
data Stmt e x where
Bind :: () -> Stmt O O
rewriter :: forall e x. Stmt e x -> Fact x () -> MyMonad (Maybe (Graph Stmt e x))
rewriter (Bind ()) () = return $ do
f <- get
if f
then return $ Just emptyGraph
else return Nothing
But this will not compile -- GHC complains that rewrite
has the wrong type:
Couldn't match expected type `Graph' Block Stmt e x'
against inferred type `Maybe (g n O O)'
Expected type: CheckingFuelMonad
(State Bool) (Maybe (Graph Stmt e x))
Inferred type: CheckingFuelMonad
(State Bool) (Maybe (Maybe (g n O O)))
Is what I want to do possible? How can I write the rewrite
function correctly?
A browse through hoopl code reveals that CheckingFuelMonad isn't an instance of MonadTrans, and you can't make it one, since its constructors are not exported. You can however wrap a StateT around CheckingFuelMonad, like so:
{-# LANGUAGE GADTs, RankNTypes #-}
import Compiler.Hoopl
import Control.Monad.State
type MyMonad = StateT Bool SimpleFuelMonad
data Stmt e x where
Bind :: () -> Stmt O O
rewriter :: forall e x. Stmt e x -> Fact x () -> MyMonad (Maybe (Graph Stmt e x))
rewriter (Bind ()) () = do
f <- get
if f
then return $ Just emptyGraph
else return Nothing
Well, the immediate cause of your current error is simple. What is the final expression if f
is true? If we take this:
rewriter :: forall e x. Stmt e x -> Fact x () -> MyMonad (Maybe (Graph Stmt e x))
rewriter (Bind ()) () = return $ do
f <- get
if f
then return $ Just emptyGraph
else return Nothing
...and remove everything but the True
branch we get:
rewriter :: forall e x. Stmt e x -> Fact x () -> MyMonad (Maybe (Graph Stmt e x))
rewriter (Bind ()) () = return $ do
return $ Just emptyGraph
...which simplifies to:
rewriter :: forall e x. Stmt e x -> Fact x () -> MyMonad (Maybe (Graph Stmt e x))
rewriter (Bind ()) () = return $ return $ Just emptyGraph
What's the type of return $ return $ Just emptyGraph
?
(Monad m1, Monad m2, GraphRep g) => m1 (m2 (Maybe (g n O O)))
In other words, you've got an extra return
in there. (Monad m) => CheckingFuelMonad m
is itself a Monad
, even though CheckingFuelMonad
doesn't seem to be defined as a monad transformer, so you've only got one monad layer to return
with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With