7

Haskellで次のデータ型を取得しました:

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

ここで、IState は、いくつかのリストなどを含むレコード タイプです。FlowT の Monad および MonadTrans インスタンスは、次のように定義されます。

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

私の意図は、私がインタープリターを開発しているおもちゃの言語では、何らかの式で return を呼び出すことで、いつでも関数から戻ることができるということでした。関数の呼び出しを解釈するコードを書いているとき、このモナドの舞台裏で渡される Flow 値を抽出する必要があります。IState() には IO が含まれているため、パターン マッチができません。私が必要とする関数は、State の get が動作するのと同様の方法で動作するはずです - 私はそれを呼び出して、何らかの値が返されているかどうかを確認できます。 . これを行う方法?

4

1 に答える 1

8

Monad値のパターン マッチを行うには、インスタンス内で行ったのとまったく同じ方法で、指定されたモナド内でその結果をバインドする必要があります。

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

余談ですが、無料のモナド変換子の特別なケースを再発明しました。それらの公式の実装はパッケージにありfreeます。

具体的には、FlowTタイプは次と同じです。

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

type FlowT = FreeT (Constant Value)

これにより、まったく同じ動作とMonadインスタンスMonadTransを持つ同型型が得られます。

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

于 2013-05-06T20:24:36.103 に答える