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 从函数中返回。现在,当我编写代码来解释函数的调用时,我需要提取在这个 monad 中在幕后传递的 Flow 值。我无法对 IState () 进行模式匹配,因为它包含 IO。我需要的函数应该以与 State 的 get 工作类似的方式工作 - 我调用它并可以检查是否返回了一些值,如果是,我得到它,如果没有,让我们说返回值类型的一些特殊值或其他东西. 这该怎么做?

4

1 回答 1

8

Monad要对值进行模式匹配,您必须将其结果绑定到给定的 monad 中,与您在实例中所做的完全相同:

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

附带说明一下,您重新发明了一个特殊的免费 monad 转换器,您可以在 package 中找到它们的官方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 回答