我正在通过例子阅读PureScript,并了解了介绍Reader的部分。例子是这样的:
createUser :: Reader Permissions (Maybe User)
createUser = do
permissions <- ask
if hasPermission "admin" permissions
then map Just newUser
else pure Nothing对我来说,令人困惑的是ask函数。签名是:
ask :: forall r. Reader r r它看起来像是在稀薄的空气中创建一个读取器
当我阅读State monad时,它和它的get函数具有相同的概念。该案文解释说:
状态是作为由state monad的数据构造函数隐藏的函数参数实现的,因此没有明确的引用可传递。
我猜这是关键,同样的事情也发生在阅读器上,但我不明白它是如何工作的.
当上面的示例通过runReader运行时,提供的值如何突然显示为ask的结果?ask的Haskell文档say:检索monad环境。但我的困惑是从哪里来的?在我看来,一个值被传递给runReader,存储在某个地方,为了得到它--你叫ask.但这毫无意义。
虽然这个例子是PureScript,但我猜任何一个懂Haskell的人也能回答,因此就使用了Haskell标签。
发布于 2017-10-13 21:37:55
我目前还没有一个PureScript环境,所以我将尝试从Haskell的角度来回答,并希望它能有所帮助。
阅读器实际上只是一个函数的“包装器”,所以当您得到一个Reader r r时,您实际上只能从r到r得到一个阅读器;换句话说,是一个函数r -> r。
你可以凭空召唤函数,因为如果你是柏拉图主义者,我想它们总是存在的.
当您使用do表示法时,您是“inside”,因此上下文r是隐式的。换句话说,您调用一个返回r值的函数,当您使用<-箭头时,您只需获得该上下文。
发布于 2018-02-24 10:42:54
您可以通过执行一些替换来使自己相信它是有效的。首先看一下createUser的签名。让我们“展开”Reader的定义
createUser :: Reader Permissions (Maybe User)
{- definition of Reader -}
createUser :: ReaderT Permissions Identity (Maybe User)ReaderT类型只有一个数据构造函数:ReaderT (r -> m a),这意味着createUser是一个计算为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、>>=和pure for 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发布于 2022-05-02 08:36:09
部分函数类型(->) r是函子,即r->a是任何类型a的容器(大小为2的List a等效于函数Bool->a)。此外,它也是一个单曲。
instance Monad ((->) r) where
f >>= k = \ r -> k (f r) r它满足MonadReader类型类,被称为简单读取器monad,并可能被赋予类型同义词Reader r。
ask返回应用于相同类型的r的monad (->) r) r,然后我们可以绑定它。
更好地理解部分函数类型(->) r。
https://stackoverflow.com/questions/46738184
复制相似问题