您可以通过执行一些替换来说服自己它有效。首先看签名createUser
。让我们“展开” 的定义Reader
:
createUser :: Reader Permissions (Maybe User)
{- definition of Reader -}
createUser :: ReaderT Permissions Identity (Maybe User)
该ReaderT
类型只有一个数据构造函数: ReaderT (r -> m a)
,这意味着createUser
是一个计算值为 type 的术语ReaderT (Permissions -> Identity (Maybe User))
。如您所见,它只是一个带有ReaderT
. 它不必凭空创建任何东西,但会在Permissions
调用该函数时接收类型的值。
现在让我们看看您遇到问题的线路。您知道do
符号只是语法糖,而表达式:
do permissions <- ask
if hasPermission "admin" permissions
then map Just newUser
else pure Nothing
脱糖
ask >>= \permissions ->
if hasPermission "admin" permissions
then map Just newUser
else pure Nothing
要了解它的作用,您必须查找ask
和>>=
forpure
的定义ReaderT
。让我们执行另一轮替换:
ask >>= \permissions -> ...
{- definition of ask for ReaderT -}
ReaderT pure >>= \permissions -> ...
{- definition of >>= for ReaderT -}
ReaderT \r ->
pure r >>= \a -> case (\permissions -> ...) a of ReaderT f -> f r
{- function application -}
ReaderT \r ->
pure r >>= \a ->
case (if hasPermission "admin" a
then map Just newUser
else pure Nothing) of ReaderT f -> f r
{- definition of pure for Identity -}
ReaderT \r ->
Identity r >>= \a ->
case (if hasPermission "admin" a
then map Just newUser
else pure Nothing) of ReaderT f -> f r
{- definition of >>= for Identity -}
ReaderT \r ->
(\a ->
case (if hasPermission "admin" a
then map Just newUser
else pure Nothing) of ReaderT f -> f r) r
{- function application -}
ReaderT \r ->
case (if hasPermission "admin" r
then map Just newUser
else pure Nothing) of ReaderT f -> f r
正如您所看到的,createUser
显然只是一个函数,ReaderT
它通过您的表达式线程化一个值(“环境”)。runReader
解包函数并使用提供的参数调用它:
runReader :: forall r a. Reader r a -> r -> a
runReader (ReaderT f) r = f r