haskell - Reader monad中本地和询问功能的目的是什么
问题描述
当我尝试熟悉 Haskell 中 Reader monad 的用法时,我注意到mtl
库中提供了两个类似的函数。
asks :: MonadReader r m => (r -> a) -> m a
local :: MonadReader r m => (r -> r) -> m a -> m a
例如,
import Control.Monad.Reader
changeEnv :: String -> String
changeEnv = ("Prefix " ++)
getLength :: Reader String Int
getLength = do
e <- ask
return $ length e
runReader (local changeEnv getLength) "123"
10
runReader (asks (length . changeEnv)) "123"
10
runReader (asks (length . local changeEnv id)) "123"
10
似乎我们可以使用asks
或来计算相同的结果local
。
是否有任何结果无法从其中任何一个计算得出?
现在,我只能说 usinglocal
允许我将changeEnv
改变环境的函数 ( getLength
) 和返回 Reader 结果的函数 () 分开。但是,同样可以实现使用asks
。
有什么特殊的原因我们需要它们吗?
解决方案
我们有asks f = local f ask
任何 f,所以你总是可以asks
用local
. 虽然通常你会认为asks f
是fmap f ask
.
然而,在另一个方向,考虑类似
local changeEnv (do x <- getLength
y <- getReverse
pure (replicate x y))
一般来说,你如何做到这一点asks
?您必须包括整个身体并明确地将环境放入其中:
asks ((\s -> replicate (length s) (reverse s)) . changeEnv)
如果您愿意,您可以随时执行此操作,因为您始终可以将任何 Reader 计算转换为普通函数。但是,您可能根本不使用 Reader。
这也不意味着local
是必要的——它只是为了方便嵌套阅读器,你总是可以runReader
直接使用,比如:
do s' <- asks changeEnv
let x = runReader (do ...) s'
...
asks
如果你真的想的话,我想你可以把它全部塞进里面,比如
asks (runReader (do ...) . changeEnv)
但使用local
似乎更好。
推荐阅读
- javascript - 如何从输入文件设置背景图像?
- ruby-on-rails - 通过 lang 获取 TMDB API
- ruby-on-rails - 带有 ActionMailer 和复杂活动记录的 Rails(连接、位置和)
- mongodb - 排序和过滤时查询慢
- laravel - Laravel 中的表单不发送数据
- dart - Flutter:将数据从 TabBarView(StatefullWidgets)发送回主 Scaffold
- magento - 如何将名称添加到 Magento 1 时事通讯
- java - 使用 threadfactory 为线程自定义命名
- wpf - 在 WPF 中添加到 UniformGrid 的子级顺序
- javascript - 如何检查是否与服务人员脱机?