Как я могу объединить CheckingFuelMonad с государственной монадой в Hoopl?
Я использую библиотеку Hoopl и хотел бы перенести некоторое состояние во время переписывания. Функции перезаписи полиморфны относительно используемой монады, но я не могу понять, как объединить State
монада с одним из библиотеки Fuel
монады.
Ниже приведен минимальный пример. MyMonad
это синоним, объединяющий Хупла CheckingFuelMonad
и State
Монада с флагом. Stmt
это просто заполнитель для моего промежуточного языка и не очень важно.
{-# 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
Но это не скомпилируется - GHC жалуется, что rewrite
имеет неправильный тип:
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)))
Возможно ли то, что я хочу сделать? Как я могу написать rewrite
функционировать правильно?
2 ответа
Просмотр кода hoopl показывает, что CheckingFuelMonad не является экземпляром MonadTrans, и вы не можете сделать его таковым, поскольку его конструкторы не экспортируются. Однако вы можете обернуть StateT вокруг CheckingFuelMonad, например так:
{-# 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
Ну, непосредственная причина вашей текущей ошибки проста. Какое окончательное выражение, если f
правда? Если мы возьмем это:
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
... и удалить все, кроме True
Ветвь получим:
rewriter :: forall e x. Stmt e x -> Fact x () -> MyMonad (Maybe (Graph Stmt e x))
rewriter (Bind ()) () = return $ do
return $ Just emptyGraph
... что упрощает:
rewriter :: forall e x. Stmt e x -> Fact x () -> MyMonad (Maybe (Graph Stmt e x))
rewriter (Bind ()) () = return $ return $ Just emptyGraph
Какой тип return $ return $ Just emptyGraph
?
(Monad m1, Monad m2, GraphRep g) => m1 (m2 (Maybe (g n O O)))
Другими словами, у вас есть дополнительный return
там. (Monad m) => CheckingFuelMonad m
само по себе Monad
, даже если CheckingFuelMonad
кажется, не определяется как преобразователь монад, поэтому у вас есть только один слой монад для return
с.