有人可以解释为什么以下(<*>)
与(=<<)
的表示有效:
f <*> a = (\f' -> return . f' =<< a) =<< f
答案 0 :(得分:8)
这让我觉得这是一种刻意迟钝的写作方式。无论谁给你这个代码都试图搞砸你。以下是ap
的通常定义,它清晰易懂:
ap f a = do
f' <- f
a' <- a
return (f' a')
我们可以通过常规do
desugaring转换运行此操作,将<-
替换为>>=
:
ap f a =
f >>= \f' ->
a >>= \a' ->
return (f' a')
现在,请注意最里面的术语是\a' -> return (f' a')
,可以写成return . f'
。
ap f a =
f >>= \f' ->
a >>= return . f'
然后,从(=<<) = flip (>>=)
开始,我们可以通过交换参数将>>=
替换为=<<
:
ap f a = f >>= (\f' -> return . f' =<< a) -- reverse inner bind
ap f a = (\f' -> return . f' =<< a) =<< f -- reverse the other bind
你去。
答案 1 :(得分:2)
名称f
和a
的使用极其令人困惑,因为名字具有暗示性(&#34; f&#34;唤起&#34;功能&#34;,但不是&#39; T)。引用名称也可能令人困惑。当您仍在学习并且不确定默认运算符优先级时,不应省略Parens。 do
的可选花括号和分号也是如此。
这两个名称应该是fs
和as
。改变它们可能是预期答案的一部分。你有
fs <*> as = (\f -> (return . f) =<< as) =<< fs
= fs >>= (\f ->
as >>= (return . f)) -- by definition of >>= and =<<
= fs >>= (\f ->
as >>= (\a -> (return . f) a)) -- by "eta expansion"
= fs >>= (\f ->
as >>= (\a -> return (f a))) -- by `(.)` reduction
= do { f <- fs
; a <- as
; return (f a) } -- by `do` syntax definition
因为这是do
语法的定义方式。那个是the definition的{/ em> ap
,其中<*>
应该是替身。
不言而喻,这只适用于不仅仅是一个应用程序,而且也适用于Monad的类型。
使用 monad comprehensions ,最后一个是
= [f a | f <- fs, a <- as]
本身很清楚。