>>=
又名 bind 有签名:m a -> (a -> m b) -> m b
. 如果我们尝试使此签名特定于 Reader,即替换m
为,Reader r
我们会发现它变成:
(Reader r) a -> (a -> (Reader r) b) -> (Reader r) b
这与以下内容相同:
Reader r a -> (a -> Reader r b) -> Reader r b
现在我们需要编写这样一个函数:
(>>=) m k = ...
在哪里,在哪里,我们m
需要返回Reader r a
k
(a -> Reader r b)
Reader r b
你怎么能创造Reader r b
,因为这是我们必须返回的东西?好吧,k
是一个允许您创建Reader r b
但k
需要一些类型值a
才能返回的函数Reader r b
。
我们如何获得类型的值a
(以便我们可以使用函数k
)?看起来m
type 的参数Reader r a
可以帮助我们获取 type 的值a
。
我们如何获得a
from的价值Reader r a
?runReader
有一个类型Reader r a -> r -> a
,所以如果我们调用我们会得到runReader
,但我们正在寻找类型的值,我们得到的是,似乎我们没有任何价值得到。似乎我们被卡住了,因为我们没有任何其他参数要寻找。m
(r -> a)
a
(r -> a)
r
a
假设我们以某种方式具有某些r
值(称为r_val
),以便我们可以这样做:
let a_val = runReader m r_val
给我们 type 的值a
。
从a
我们需要得到Reader r b
使用 k
let reader_r_b_val = k a_val
给了我们类型的值Reader r b
,就是这样,我们得到了我们需要返回的东西,让我们结合以上两个让:
k (runReader m r_val)
但是我们还Reader r b
没有完成,我们需要做一些r_val
只是占位符的事情。假设我们将r_val
其作为参数
\r_val -> k (runReader m r_val)
这是类型r -> Reader r b
... 嗯,但我们只需要返回Reader r b
.. 我们可以以某种方式包装r -> Reader r b
成 aReader r b
吗?
Reader $ (\r_val -> k (runReader m r_val))
有一个类型Reader r (Reader r b)
.. 看起来我们快到了,我们只需要转换Reader r (Reader r b)
为,Reader r b
即我们需要将 inner 转换Reader r b
为 just b
,为此我们可以使用runReader
:
Reader $ (\r_val -> runReader (k (runReader m r_val)) r_val)