我在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
我的意图是,在我正在开发解释器的玩具语言中,您可以随时通过调用带有某种表达式的返回来从函数返回。现在当我编写代码来解释函数的调用时,我需要提取在这个monad中幕后传递的Flow值。我无法与IState()进行模式匹配,因为它包含IO。我需要的函数应该以类似于State的方式工作 - 我调用它并且可以检查是否返回了一些值,如果是,我得到它,如果没有让我们说一些特殊值的Value返回或者某些东西。怎么做?
答案 0 :(得分:8)
要对值进行模式匹配,您必须在给定的monad中绑定其结果,与您在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)
这给出了一个具有完全相同行为和相同Monad
和MonadTrans
个实例的同构类型。
但回到你的具体问题:不,没有办法在没有首先在基础monad中绑定结果的情况下对值进行模式匹配。