Как я могу объединить 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 с.

Другие вопросы по тегам