簡體   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