2011-06-27 23 views
7

我正在使用Hoopl庫,並希望在重寫時進行一些操作。重寫函數對於使用的monad是多態的,但是我不知道如何將State monad與其中一個庫的Fuel monad結合在一起。如何將CheckingFuelMonad與Hoopl中的狀態單元組合起來?

下面是一個簡單的例子。 MyMonad是Hoopl的CheckingFuelMonadState 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函數?

+0

我超級不服,認爲這個重寫是正確的。這是非常狡猾的生意。 –

回答

4

瀏覽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 
+0

有趣的是,如果你看看'CheckingFuelMonad'的實現,它本身就是'StateT Fuel'。 –

+0

這有助於我獲得更遠一點!不幸的是'MyMonad'必須是'FuelMonad'的一個實例,並且我不認爲我可以讓它成爲一個類,因爲類成員不會被導出。但是,我可以用'mkBRewrite(\ s f - > evalStateT(重寫器s f)False)'離開。不幸的是,我認爲這意味着國家將不會在個人陳述中保留 - 我們將會看到! –

+0

@Justin Bailey:從'FuelMonad'看起來好像它已經出口給我了。另外,我很確定這個順序與*相鄰的*'StateT'圖層無關,所以'sclv'的版本應該等同於將'State'放入'SimpleFuelMonad'中。 –

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變換器,所以你只有一個單層到return

+0

剝回關導致另一種類型的錯誤... :( –

+0

@Justin貝利:所以爲什麼我說「直接原因」卸下'return'的'do'塊外面只是它減少到實際問題,這是。什麼'sclv'談論。 –

相關問題