函数本地 haskell Reader monad

Function local haskell Reader monad

我考虑下面两个表达式是否等价:

env <- ask
local (\_ -> env) sth

和:

local (\env -> env) sth

如果不是,参数 lambda 被带到哪里?

不太确定你的问题是什么,但让我们试一试。

所以你问的是

ask >>= \env -> local (const env) sth

local id sth

是等价的。

就效果而言 -- 当然是。更重要的是,它们都等同于 sth。让我们考虑一个稍微复杂一点的例子:

ask >>= \env -> local (const (f env)) sth

local f sth

现在让我们试着了解它是如何工作的。

local 定义为

local :: (r -> r) -> Reader r a -> Reader r a
local f m = Reader $ runReader m . f

(我简化了一点,因为它实际上是通过 withReaderTReaderT 定义的,但它理解了这个想法)

提醒一下,我们可以假设

runReader :: Reader r a -> r -> a

此外,提醒一下 Reader r a 是一种包装 r -> a.

的新类型

现在,>>= 在这里做什么?简单,

m >>= k  = Reader $ \r -> runReader (k (runReader m r)) r

因此,它需要 m,从中提取值,并将其传递给 k,同时将实际环境 r 作为自由参数。作为一个行为良好的 monadic bind 应该,所以这里不足为奇。

还要注意,ask 只是 Reader id

现在,让我们完全放弃整个 Reader 东西,将我们的表达式重写为函数。

ask >>= \env -> local (const (f env)) sth

然后变成

\r -> (\r' -> runReader sth (const (f r) r')) r

local f sth

变成

\r -> runReader sth (f r)

现在稍微眯一下,就可以看出这两者在效果上是等价的。的确,

const (f r) r' = f r
(\r' -> runReader sth (f r)) r = (\_ -> runReader sth (f r)) r
                               = runReader sth (f r)

所以

\r -> (\r' -> runReader sth (const (f r) r')) r

变成

\r -> runReader sth (f r)

local f sth完全相同。

现在的问题是,您的编译器是否足够聪明,可以自行执行此 t运行sformation?如果非要我猜的话,我猜 GHC 确实足够聪明,因为它都是基本的代数等式。但幸运的是,我没有去猜测,因为我可以检查。

使用这两个来源,test1.hs:

import Control.Monad.Reader

main :: IO ()
main = print $ runReader m "hello"

f = (++"!!!")

m = ask >>= \r -> local (const (f r)) ask

test2.hs:

import Control.Monad.Reader

main :: IO ()
main = print $ runReader m "hello"

f = (++"!!!")

m = local f ask

I 运行 ghc -O2 -ddump-simpl 在他们两个上(使用 GHC 7.10.3)。猜猜是什么,核心文件仅在 运行domized 名称上有所不同。

G运行ted,没有 -O2 输出差异很大。但这是意料之中的。