>>=又名 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 ak(a -> Reader r b)Reader r b
你怎么能创造Reader r b,因为这是我们必须返回的东西?好吧,k是一个允许您创建Reader r b但k需要一些类型值a才能返回的函数Reader r b。
我们如何获得类型的值a(以便我们可以使用函数k)?看起来mtype 的参数Reader r a可以帮助我们获取 type 的值a。
我们如何获得afrom的价值Reader r a?runReader有一个类型Reader r a -> r -> a,所以如果我们调用我们会得到runReader,但我们正在寻找类型的值,我们得到的是,似乎我们没有任何价值得到。似乎我们被卡住了,因为我们没有任何其他参数要寻找。m(r -> a)a(r -> a)ra
假设我们以某种方式具有某些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)