了解简单Reader Monad的do表示法:a<-(* 2),b<-(+10),return(a + b) [英] Understanding do notation for simple Reader monad: a <- (*2), b <- (+10), return (a+b)
问题描述
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
import Control.Monad.Instances
addStuff :: Int -> Int
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
我试图通过松开do符号来理解此monad,因为我认为do符号隐藏了会发生的事情.
I'm trying to understand this monad by unwiding the do notation, because I think the do notation hides what happens.
如果我理解正确,就会发生这种情况:
If I understood correctly, this is what happens:
(*2) >>= (\a -> (+10) >>= (\b -> return (a+b)))
现在,如果采用>>=
的规则,则必须将(*2)
理解为h
,将(\a -> (+10) >>= (\b -> return (a+b)))
理解为f
.将h
应用于w
很容易,我们只说它是2w
(我不知道2w
在haskell中是否有效,但出于推理的原因,请保持这种方式.现在我们必须应用h w
或2w
.f
只需为特定的a
返回(+10) >>= (\b -> return (a+b))
,在我们的例子中为2w
,因此f (hw)
为(+10) >>= (\b -> return (2w+b))
.最终在将其应用于w
之前发生在(+10) >>= (\b -> return (2w + b))
上.
Now, if we take the rule for >>=
, we must understand (*2)
as h
and (\a -> (+10) >>= (\b -> return (a+b)))
as f
. Applying h
to w
is easy, let's just say it is 2w
(I don't know if 2w
is valid in haskell but just for reasoning lets keep it this way. Now we have to apply f
to h w
or 2w
. Well, f
simply returns (+10) >>= (\b -> return (a+b))
for an specific a
, which is 2w
in our case, so f (hw)
is (+10) >>= (\b -> return (2w+b))
. We must first get what happens to (+10) >>= (\b -> return (2w + b))
before finally applying it to w
.
现在,我们用规则重新标识(+10) >>= (\b -> return (2w + b))
,因此h
是+10
,而f
是(\b -> return (2w + b))
.让我们首先执行h w
.我们得到w + 10
.现在我们需要将f
应用于h w
.我们得到(return (2w + w + 10))
.
Now we reidentify (+10) >>= (\b -> return (2w + b))
with our rule, so h
is +10
and f
is (\b -> return (2w + b))
. Let's first do h w
. We get w + 10
. Now we need to apply f
to h w
. We get (return (2w + w + 10))
.
所以我们要在第一个>>=
中尝试将(return (2w + w + 10))
应用于w
.但是我完全迷路了,不知道发生了什么.
So (return (2w + w + 10))
is what we need to apply to w
in the first >>=
that we were tyring to uwind. But I'm totally lost and I don't know what happened.
我在以严格的方式思考吗?这真令人困惑.有没有更好的方法来考虑它?
Am I thinking in the rigth way? This is so confusing. Is there a better way to think of it?
推荐答案
您忘记了运算符>>=
不仅返回f (h w) w
,而且还返回\w -> f (h w) w
.也就是说,它返回一个函数,而不是数字.
You're forgetting that operator >>=
doesn't return just f (h w) w
, but rather \w -> f (h w) w
. That is, it returns a function, not a number.
通过错误地替换它,您丢失了最外面的参数w
,因此也就不足为奇了,它在最终表达式中仍然是免费的.
By substituting it incorrectly you lost the outermost parameter w
, so it's no wonder it remains free in your final expression.
要正确执行此操作,您必须完全用函数主体代替它们的调用,而不能丢弃任何东西.
To do this correctly, you have to substitute function bodies for their calls completely, without dropping stuff.
如果用最外面的>>=
代替,则会得到:
If you substitute the outermost >>=
, you will get:
(*2) >>= (\a -> ...)
==
\w -> (\a -> ...) (w*2) w
然后,如果替换最里面的>>=
,则会得到:
Then, if you substitute the innermost >>=
, you get:
\a -> (+10) >>= (\b -> return (a+b))
==
\a -> \w1 -> (\b -> return (a+b)) (w1 + 10) w1
请注意,我使用的是w1
而不是w
.这是为了避免以后在组合替换项时发生名称冲突,因为这两个w
来自两个不同的lambda抽象,因此它们是不同的变量.
Note that I use w1
instead of w
. This is to avoid name collisions later on when I combine the substitutions, because these two w
s come from two different lambda abstractions, so they're different variables.
最后,用return
代替:
return (a+b)
==
\_ -> a+b
现在将最后一个替换项插入上一个替换项:
Now insert this last substitution into the previous one:
\a -> (+10) >>= (\b -> return (a+b))
==
\a -> \w1 -> (\b -> return (a+b)) (w1 + 10) w1
==
\a -> \w1 -> (\b -> \_ -> a+b) (w1 + 10) w1
最后将其插入到第一个替换中:
And finally insert this into the very first substitution:
(*2) >>= (\a -> ...)
==
\w -> (\a -> ...) (w*2) w
==
\w -> (\a -> \w1 -> (\b -> \_ -> a+b) (w1 + 10) w1) (w*2) w
现在所有的替代品都在竞争,我们可以减少.首先应用最里面的lambda \b -> ...
:
And now that all substitutions are compete, we can reduce. Start with applying the innermost lambda \b -> ...
:
\w -> (\a -> \w1 -> (\_ -> a+w1+10) w1) (w*2) w
现在应用新的最里面的lambda \_ -> ...
:
Now apply the new innermost lambda \_ -> ...
:
\w -> (\a -> \w1 -> a+w1+10) (w*2) w
现在申请\a -> ...
:
\w -> (\w1 -> w*2+w1+10) w
最后应用剩下的唯一lambda \w1 -> ...
:
And finally apply the only remaining lambda \w1 -> ...
:
\w -> w*2+w+10
瞧!整个功能降低到\w -> (w*2) + (w+10)
,完全符合预期.
And voila! The whole function reduces to \w -> (w*2) + (w+10)
, completely as expected.
这篇关于了解简单Reader Monad的do表示法:a<-(* 2),b<-(+10),return(a + b)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!