2011-06-27 13 views
7

私はHooplライブラリを使用しており、書き換え中に何らかの状態を保持したいと考えています。書き換え関数は使用されているモナドに関する多型ですが、StateモナドとライブラリのFuelモナドのいずれかをどのように組み合わせるか分かりません。CheckingFuelMonadとHooplのStateモナドを組み合わせるにはどうすればいいですか?

以下は最小の例です。 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関数を正しく書くにはどうすればよいですか?

+0

私はこの書き換えが健全であることを納得していません。これは非常に厄介なビジネスです。 –

答えて

4

hooplコードを参照すると、CheckingFuelMonadはMonadTransのインスタンスではなく、そのコンストラクタがエクスポートされないため、CheckingFuelMonadをMonadTransのインスタンスにすることはできません。

{-# 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(rewriter s f)False)'で逃げることができます。残念ながら私はそれが状態が個々のステートメントの間保存されないことを意味すると思います。 –

+0

@Justin Bailey:「FuelMonad」からのすべては、それが私に輸出されたように見えます。また、隣接する 'StateT'レイヤーとのオーダーは関係ないので、' sclv'のバージョンは 'SimpleFuelMonad'の中に' State'を置くのと同じでなければなりません。 –

1

さて、あなたの現在のエラーの直接の原因は簡単です:あなたははそうは次のように、CheckingFuelMonad周りStateTを包むしかしことができます。 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 $ return $ Just emptyGraph 

:に簡素化

rewriter :: forall e x. Stmt e x -> Fact x() -> MyMonad (Maybe (Graph Stmt e x)) 
rewriter (Bind())() = return $ do 
    return $ Just emptyGraph 

を... return $ return $ Just emptyGraph?言い換えれば

(Monad m1, Monad m2, GraphRep g) => m1 (m2 (Maybe (g n O O))) 

、あなたはそこに余分なreturnを持っています。 CheckingFuelMonadはモナド変換器として定義されていないようですが、returnには1つのモナド層しかありませんが、(Monad m) => CheckingFuelMonad mはそれ自体がMonadです。

+0

戻り値を削除すると、別の型エラーが発生します。:( –

+0

@Justin Bailey:なぜ「即時の原因」と言われましたか? 'do'ブロックの外にある' return'を削除すると、実際の問題になります。 'sclv'が語っていること。 –

関連する問題