我在学习haskell monad变形金刚时遇到了这个问题。
假设我有一个instance Monad m => Monad (CustomT m)
类型。
如果有f :: CustomT IO Int
功能,那就是g :: IO (Maybe Int)
。
如何访问Int
中g
的{{1}}?
我试过像
这样的东西f
这不起作用,因为f = do
mVal <- g
位于f
monad下,而CustomT IO
位于g
monad下。
然后我尝试了
MaybeT IO
这似乎有效但f = do
mVal <- return g
为mVal
类型,我最终会像IO (Maybe Int)
IO
有没有办法在CustomT IO (IO something)
中获取Int
或Maybe Int
?
涉及哪些知识? 提前谢谢。
答案 0 :(得分:3)
在一般情况下,Jeremy的答案就是你想要的。但是,让我们看看我们是否可以在这里处理您的具体案例。我们有f :: CustomT IO Int
和g :: IO (Maybe Int)
,因为instance Monad m => Monad (CustomT m)
和instance MonadTrans CustomT
有一些实例。
你想要的是在Int
的上下文中g
内的CustomT IO
。由于我们在CustomT
内部,我们基本上可以轻松剥离该层。就像杰里米说的那样,用lift
来摆脱它。
lift :: (MonadTrans t, Monad m) => m a -> t m a
现在我们有了CustomT IO (Maybe Int)
。就像我说的那样,我们在do
- 块内,所以使用Haskell的bind(<-
)语法暂时删除monad层。因此,我们正在处理Maybe Int
。要从Maybe Int
转到Int
,通常的方法是使用maybe
maybe :: b -> (a -> b) -> Maybe a -> b
这提供了默认值,以防Maybe Int
实际为Nothing
。因此,例如,maybe 0 id
是一个函数,它接受Maybe Int
并产生内部Int
或0
,如果值为Nothing
。所以,最后,我们有:
f = do
mVal <- maybe 0 id $ lift g
-- Other code
答案 1 :(得分:2)
在Control.Monad.Trans
中你有monad变换器的这个定义:
class MonadTrans (t :: (* -> *) -> * -> *) where
lift :: Monad m => m a -> t m a
这意味着如果CustomT
已正确定义,您可以执行此操作:
f = do
mVal <- lift g