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