我有以下代码段,无法配置它,它是如何工作的:
embedded :: MaybeT (ExceptT String (ReaderT () IO)) Int
embedded = return 1
如何才能只提供一个数字并获得类型签名?编译器如何做到这一点?
答案 0 :(得分:10)
措辞的选择有点不幸。表达式return 1
不会返回类型签名MaybeT (ExceptT String (ReaderT () IO)) Int
。
正如 n.m。在评论中写道,如果你不提供类型,表达式会更加通用:
Prelude> embedded = return 1
Prelude> :type embedded
embedded :: (Num a, Monad m) => m a
通过使用类型进行注释,您明确声明您想要的东西不是那么普通。
具体而言,您声明您需要类型MaybeT (ExceptT String (ReaderT () IO)) Int
。
return
如何运作?当MaybeT m a
为Monad
时,m
为Monad
,return
的定义如下:
return = lift . return
右侧return
是return
函数,属于'内部' Monad
,而lift
由MonadTrans
定义,并将基础monadic值提升至MaybeT
。
这解释了如何创建MaybeT
值,但不是整个故事。
在这种情况下,'内部' Monad
是ExceptT String (ReaderT () IO)
,这是另一个Monad
(实际上是另一个MonadTrans
)。 return
的定义如下:
return a = ExceptT $ return (Right a)
请注意,这是另一个嵌套return
,其中右侧return
属于另一个嵌套Monad
。
在这种情况下,嵌套的Monad
为ReaderT () IO
- 另一个MonadTrans
。它定义return
,如下所示:
return = lift . return
另一个嵌套return
,其中右侧return
是为return
定义的IO
(在此特定情况下)。
所有这些都是使用a
进行参数化的,在这种情况下,您已限制为Int
。
因此return 1
首先获取纯值1
并将其打包在IO Int
中。然后将其提升到ReaderT () IO Int
,再次打包成ExceptT String (ReaderT () IO) Int
。最后,这些值被提升到MaybeT
。