haskell - 为什么 ask 从 Reader monad 中检索环境

2 monads haskell

我无法理解这一点:

假设t隐藏一个读者单子里面。

我可以使用ask

do
   x <- ask
   ...
Run Code Online (Sandbox Code Playgroud)

它将 隐藏的值解包x

现在我试图了解>>=会做什么,但我很挣扎。

你能向我解释一下吗?


这是我的尝试:

f = \x -> x  

ask >>= (\x -> return x) 
= Reader $ \r -> f (ask (r))  r 
{ using the fact that ask is identity }
= Reader $ \r -> f(r) r 
Run Code Online (Sandbox Code Playgroud)

但是,我不明白这是如何达到隐藏 值的

Car*_*ten 5

我认为主要的一点是,里面真的没有任何隐藏的东西Reader- 相反它是一个函数 -当你运行阅读器时你的隐藏值进入了阶段(这是当向阅读器显示你的隐藏值并让它评估一些输出)。

重温定义

好吧,让我们稍微简化一下,并假设我们的ReaderMonad的结构定义如下:

data Reader h a = Reader { run :: h -> a }
Run Code Online (Sandbox Code Playgroud)

这意味着您隐藏的值将具有某种类型h,并且Reader它只是一个函数,a当出现这样的值时,它会产生一些其他值(类型)。

正如你可以看到有没有隐藏在所有的价值-你当自己提供它运行Readerrun

下面是一个例子:

showInt :: Reader Int String
showInt = Reader show
Run Code Online (Sandbox Code Playgroud)

你会像这样使用它

?> run showInt 5
"5" -- has type :: String
Run Code Online (Sandbox Code Playgroud)

让它成为 Monad

Monad 实例基本上就是这个(你必须为Applicativeand提供实例Functor,我将跳过)

instance Monad (Reader h) where 
    return v =
      Reader (const v)
    r >>= f  = Reader $ \ h ->
      let v = run r h
          r' = f v
      in run r' h
Run Code Online (Sandbox Code Playgroud)

请注意您如何再次等待有人为您提供h(通过调用run),然后:

  • 首先v使用读取器获取值run r h
  • 用它v来获得另一个读者f'
  • 最终通过使用相同的 方式运行它来获得这个阅读器的价值hrun r' h

什么是 ask

正如你所说:它只是读者使用id- 它会在运行时重现给定的值:

ask :: Reader h h
ask = Reader id
Run Code Online (Sandbox Code Playgroud)

你的问题

现在我们终于可以解决这个问题了:

如果我们跑会发生什么

let r = ask >>= (\x -> return x) 
Run Code Online (Sandbox Code Playgroud)

好吧,让我们在:

run r "Hello"
{ def r }
= run (ask >>= return) "Hello"
{ def >>= }
= run (\h ->
   let v  = run ask h
       r' = return v
   in run r' h) "Hello"
{ def run: plug "Hello" into h }
 = let v  = run ask "Hello"
       r' = return v
   in run r' "Hello"
{ ask = Reader id - so run ask "Hello" = "Hello" -> v = "Hello" }
= let r' = return "Hello"
  in run r' "Hello"
{ simplify }
= run (return "Hello") "Hello"
{ r' = const "Hello" = \ _ -> "Hello" }
= (\ _ -> "Hello") "Hello"
{ apply }
= "Hello"
Run Code Online (Sandbox Code Playgroud)

法律

顺便说一句:它以这种方式解决是一件好事,因为其中一个 monad-laws(它应该成立但不是由 Haskell 强制执行)指出:

m >>= return == m
Run Code Online (Sandbox Code Playgroud)

这意味着在这里,您的读者 ask >>= return == ask

这会让这一切变得更容易;)