繁体   English   中英

从 Applicative 和 Monad 证明序列定义的等效性

[英]Proving equivalence of sequence definitions from Applicative and Monad

我怎样才能正确地证明这一点

sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
sequenceA []     = pure []
sequenceA (x:xs) = pure (:) <*> x <*> sequenceA xs

本质上与 monad 输入相同

sequenceA' :: Monad m => [m a] -> m [a]
sequenceA' [] = return [] 
sequenceA' (x:xs) = do 
                    x'  <- x 
                    xs' <- sequenceA' xs 
                    return (x':xs')

当然,尽管有ApplicativeMonad的约束。

这是一个证明草图:

  1. 显示

    do x' <- x xs' <- sequenceA' xs return (x' : xs')

    相当于

    do f1 <- do cons <- return (:) x' <- x return (cons x') xs' <- sequenceA' xs return (f1 xs')

    这涉及脱糖(和重新加糖) do符号和应用Monad 定律

  2. 使用ap定义

     ap m1 m2 = do { x1 <- m1; x2 <- m2; return (x1 x2) }

    把上面的代码变成

    do f1 <- return (:) `ap` x xs' <- sequenceA' xs return (f1 xs')

    进而

    return (:) `ap` x `ap` sequenceA' xs
  3. 现在你有

    sequenceA' [] = return [] sequenceA' (x:xs) = return (:) `ap` x `ap` sequenceA' xs

    假设pure<*>本质上分别与return`ap`相同,那么您就完成了。

    Applicative 文档中也说明了后一个属性:

    如果f也是一个Monad ,它应该满足

    • pure = return

    • (<*>) = ap

由于在 GHC 7.10 中实现的Functor-Applicative-Monad 提案,Applicative 是 Monad 的超类。 因此,即使您的两个函数不能严格等效,因为sequenceA的域包括sequenceA' ' 的域,我们可以看看在这个公共域( Monad类型类)中发生了什么。

本文所示脱糖的一个有趣的演示do记号,以应用性和仿函数操作( <$> pure<*> 如果你的左箭头 ( <- ) 右侧的表达式不相互依赖,就像你的问题一样,你总是可以使用应用运算,因此表明你的假设是正确的(对于Monad域)。

另请查看ApplicativeDo语言扩展提案,其中包含一个与您类似的示例:

do
  x <- a
  y <- b
  return (f x y)

这意味着:

(\x y -> f x y) <$> a <*> b

f代替(:) ,我们得到:

do
  x <- a
  y <- b
  return (x : y)

......这翻译成......

(\x y -> x : y) <$> a <*> b
--And by eta reduction
(:) <$> a <*> b
--Which is equivalent to the code in your question (albeit more general):
pure (:) <*> a <*> b

或者,您可以通过使用ApplicativeDo语言扩展并按照对 SO 问题“haskell - Desugaring do-notation for Monads”的回答来使 GHC 的 desugarer 为您工作。 我会把这个练习留给你(因为它真的超出了我的能力!)。

我自己的两分钱

Haskell 中没有应用程序的 do 符号。 可以在这部分具体看到。

returnpure完全一样,但有不同的约束,对吧?所以这部分pure (:)和这部分return (x:xs)本质上是一样的。

然后,在这里x <- act你得到的是 act 的值,然后是递归xs <- seqn acts act 的值,最后用return包裹它。

这就是pure (:) <*> x <*> sequenceA xs本质上所做的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM