我目前正在研究monad和applicative functors之间的关系。
我看到ap的两个实现:
ap m1 m2 = do { f <- m1 ; x <- m2 ; return (f x) }
和
ap m1 m2 = do { x <- m2 ; f <- m1 ; return (f x) }
第二个是不同的,但它是<*>
的一个很好的实现吗?
我迷失在pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
我试图直观地了解&#34; monad的哪一部分是应用函子&#34; ...
答案 0 :(得分:17)
这个问题至少有三个相关方面。
给定一个Monad m
实例,其必要的Applicative m
超类实例的规范是什么? 答案:pure
为return
,<*>
为ap
,所以
mf <*> ms == do f <- mf; s <- ms; return (f s)
请注意,此规范不是Applicative
类的法则。这是Monad
的要求,以确保一致的使用模式。
鉴于该规范(通过候选实现),ap
是唯一可接受的实现。 回答:响亮,没有。 >>=
类型允许的值依赖性有时会导致执行效率低下:在某些情况下,<*>
可以比ap
更高效,因为您不需要等待在你可以告诉第二次计算是什么之前完成第一次计算。 &#34;应用程序&#34;记谱法确实存在于利用这种可能性。
Applicative
的任何其他候选实例是否满足Applicative
法律,即使他们不同意所需的ap
实例? 回答:是的。 &#34;向后&#34;问题提出的实例就是这样的事情。事实上,正如另一个答案所指出的那样,任何一个应用都可以倒退,结果通常是不同的野兽。
对于读者的进一步示例和练习,请注意非空列表是普通列表中熟悉的单词。
data Nellist x = x :& Maybe (Nellist x)
necat :: Nellist x -> Nellist x -> Nellist x
necat (x :& Nothing) ys = x :& Just ys
necat (x :& Just xs) ys = x :& Just (necat xs ys)
instance Monad Nellist where
return x = x :& Nothing
(x :& Nothing) >>= k = k x
(x :& Just xs) >>= k = necat (k x) (xs >>= k)
至少找到符合适用法律的四个行为不同的Applicative Nellist
实例。
答案 1 :(得分:6)
让我们从一个显而易见的事实开始:IsEmail
这样的定义违反了<*>
法律,ap
<*>
ap
应该ap
,Monad
是ap
类中定义的那个,即您发布的第一个。
除了琐事之外,据我所知,其他适用法律应该成立。
更具体地说,让我们关注你提到的构成法。
你的“逆转”(<**>) m1 m2 = do { x <- m2 ; f <- m1 ; return (f x) }
(<**>) m1 m2 = pure (flip ($)) <*> m2 <*> m1
也可以定义为
<*>
其中ap
是“常规”u <**> (v <**> w) =
{ def. <**> }
pure (flip ($)) <*> (v <**> w) <*> u =
{ def. <**> }
pure (flip ($)) <*> (pure (flip ($)) <*> w <*> v) <*> u =
{ composition law }
pure (.) <*> pure (flip ($)) <*> (pure (flip ($)) <*> w) <*> v <*> u =
{ homomorphism law }
pure ((.) (flip ($))) <*> (pure (flip ($)) <*> w) <*> v <*> u =
{ composition law }
pure (.) <*> pure ((.) (flip ($))) <*> pure (flip ($)) <*> w <*> v <*> u =
{ homomorphism law (x2)}
pure ((.) ((.) (flip ($))) (flip ($))) <*> w <*> v <*> u =
{ beta reduction (several) }
pure (\x f g -> g (f x)) <*> w <*> v <*> u
。
这意味着,例如,
pure (.) <**> u <**> v <**> w = ...
(我希望我能把一切都搞定)
尝试做类似于左手边的事情。
for i in range(100):
if i%(2*n) < n :
fun1()
else:
fun2()