Как я могу объединить CheckingFuelMonad с государственной монадой в Hoopl? - PullRequest
7 голосов
/ 27 июня 2011

Я использую библиотеку 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 ]

4 голосов
/ 27 июня 2011

Просмотр кода 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
1 голос
/ 27 июня 2011

Ну, непосредственная причина вашей текущей ошибки проста. Каково окончательное выражение, если 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 с.

...