2013-05-06 3 views
7

私は次しまったデータの種類:ISTATEのように定義されているFlowTのためのいくつかのリストなどモナドとMonadTransインスタンスを含むいくつかのレコードタイプがあるパターンマッチ

data Flow a = Continue a | Return Value 
newtype FlowT m a = FlowT {runFlowT :: m (Flow a)} 
type IStateM a = FlowT (StateT IState IO) a 

は、次のとおりです。

instance (Monad m) => Monad (FlowT m) where 
x >>= f = FlowT $ do 
        unwrapped <- runFlowT x 
        case unwrapped of 
         Continue v -> runFlowT (f v) 
         Return r -> return $ Return r 
return x = FlowT $ return (Continue x) 


instance MonadTrans FlowT where 
    lift m = FlowT (Continue `liftM` m) 

instance (MonadIO m) => MonadIO (FlowT m) where 
    liftIO m = lift (liftIO m) 

instance (MonadState s m) => MonadState s (FlowT m) where 
    put k = lift (put k) 
    get = lift get 

私が通訳を開発しているおもちゃの言語では、何らかの表現でリターンを呼び出すことによって、いつでも関数から戻ることができます。今では関数の呼び出しを解釈するコードを書くときに、このモナドのシーンの裏に渡されるFlow値を抽出する必要があります。 IOが含まれているため、IState()とのパターンマッチングはできません。私が必要とする関数はStateのget関数と同様に動作するはずです - 私はそれを呼び出し、返される値があるかどうかを調べることができます。もしそうなら、値を返す何か特別な値。これを行う方法?

答えて

8

値のパターンと一致するように、あなたが与えられたモナド、あなたはMonadインスタンス内でやったとまったく同じ方法以内にその結果をバインドする必要があります。注意点として

interpret :: FlowT m a -> m a 
interpret flow = do 
    value <- runFlowT flow 
    case value of 
     Continue v -> ... 
     Return r -> ... 

、あなたは特別なを再発明しましたケースはfree monad transformersで、the free packageに公式に実装されています。

具体的には、あなたのFlowTタイプは同じです:

import Control.Monad.Trans.Free -- from the 'free' package 
import Data.Functor.Constant  -- from the 'transformers' package 

type FlowT = FreeT (Constant Value) 

これはまったく同じ動作と同じMonadMonadTransインスタンスと同型の種類を提供します。

あなたの特定の質問に戻ります:いいえ、最初にベースモナド内に結果をバインドせずに、値にパターンマッチングする方法はありません。

+0

私はそれがどのように可能かはわかりませんが、私は以前これを試したことがあり、うまくいかないと確信しています。しかし、あなたのポストを読んで私のコードを書き直した後、私は魔法のように動作させました。私は何が間違っていたのか分かりません:)私はControl.Monad.Trans.Freeについて知りませんでした。助けてくれてありがとう –

+0

それは私にも起こります、心配しないでください。 :) –

関連する問題