如何将CheckingFuelMonad与Hoopl中的State monad结合使用?

时间:2011-06-27 15:36:11

标签: haskell monads state-monad hoopl

我正在使用Hoopl库,并希望在重写时携带一些状态。重写函数对于使用的monad是多态的,但我无法弄清楚如何将State monad与库的Fuel monad组合。

以下是一个最小的例子。 MyMonad是Hoopl的CheckingFuelMonad和携带旗帜的State monad的同义词。 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 个答案:

答案 0 :(得分:4)

浏览hoopl代码显示,CheckingFuelMonad不是MonadTrans的实例,并且您不能将其设置为一个,因为它的构造函数不会导出。你可以然后在CheckingFuelMonad周围包装一个StateT,如下所示:

{-# 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 :(得分:1)

那么,您当前错误的直接原因很简单。如果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似乎没有被定义为monad变换器,所以你只有一个monad层到return