2014-12-03 92 views
14

爲什麼當你定義函數複製Comonad複製功能

duplicate :: w a -> w (w a)  

的Comonad類型類(link),你必須修改「的背景下,」所有元素(即更改除當前其他元素值的上下文)。爲什麼不只是使用類似的東西在Monad中返回

例(拉鍊):

data Z a = Z [a] a [a]  

,爲什麼我就不能定義重複的

duplicate z = Z [] z []  

我試圖得到要求的從Comonad規則複製功能,但我總最後得到一個重複的東西,就像返回一樣,它不需要做任何其他事情。

一個blog post說:

重複是有點難以把握。從列表拉鍊,我們必須建立列表拉鍊的列表拉鍊。這背後的意義(由共同法律證實,每個實例都必須履行)是在複製結構內移動返回原來的結構,由相同的移動改變

但我不明白爲什麼它必須是那樣。該FMAP在Comonad規則始終適用於包裝的元素,後來這一個元素總是「展開」與提取,何苦做別的事情在重複其他不僅僅是包裝的參數複製功能?

你能指出我錯過了什麼嗎?我覺得我在某個地方犯了一些明顯的錯誤,但我自己無法弄清楚。

在此先感謝您的回覆!

+0

你可能會對這個問題感興趣,這個問題是關於一般爲任何可區分類型派生用於拉鍊的comonad實例的。 http://stackoverflow.com/q/25554062/414413如果是這樣,請檢查pigworker廣泛的解決方案與偏微分方程或我的解決方案與二階導數。 – Cirdec 2014-12-03 20:43:39

+0

感謝您的鏈接,當我試圖找到我的問題的答案時,我滾動它,但現在當您明確推薦它時,我發現它有大量新東西供我思考。我肯定會研究它。 – Jackie 2014-12-05 09:58:12

回答

6

重要的是,如果您可以使用其他類型的東西,而不僅僅是extract。直觀地說,如果你能做的唯一事情就是提取值,那麼類型只保存一個值,所以複製那個值就是複製所有的東西。這通常不是真實的,拉鍊不是這樣。

Comonad法律只是w a -> b類型的功能變相的類別法律。由於這些來自類別,因此就類別而言可能比根據Comonad法則更容易推理它們。 extract是此類別的標識,並且=<=是組合運算符。

-- | Right-to-left 'Cokleisli' composition 
(=<=) :: Comonad w => (w b -> c) -> (w a -> b) -> w a -> c 
f =<= g = f . extend g 

我們也知道,extend f = fmap f . duplicate,所以我們可以寫

f =<= g = f . fmap g . duplicate 

這看起來很容易推理。現在,讓我們爲您的Z類型配備另一個我們可以談論的功能。 isFirst只有在Z表示一個列表中某個位置上的某個值時纔會返回true,前面沒有任何值。

isFirst :: Z a -> Bool 
isFirst (Z [] _ _) = True 
isFirst _   = False 

現在,讓我們來看看會發生什麼,當我們使用isFirst與三個類別的法律。似乎只有兩個立即適用於它extract是由=<=組成的左和右身份。既然我們只是在反駁這一點,我們只需要找到一個反例。我懷疑extract =<= isFirstisFirst =<= extract之一會因輸入Z [1] 2 []而失敗。這兩者應該與isFirst $ Z [1] 2 []相同,即False。我們將首先嚐試extract =<= isFirst,這恰好可以解決。

extract =<= isFirst    $ Z [1] 2 [] 
extract . fmap isFirst . duplicate $ Z [1] 2 [] 
extract . fmap isFirst $ Z []   (Z [1] 2 []) [] 
extract    $ Z [] (isFirst (Z [1] 2 [])) [] 
extract    $ Z [] False     [] 
           False 

當我們嘗試isFirst =<= extract我們不會那麼幸運。

isFirst =<= extract    $ Z [1] 2 [] 
isFirst . fmap extract . duplicate $ Z [1] 2 [] 
isFirst . fmap extract $ Z []   (Z [1] 2 []) [] 
isFirst    $ Z [] (extract (Z [1] 2 [])) [] 
isFirst    $ Z [] 2      [] 
True 

當我們duplicate d我們失去了對結構的信息。事實上,除了拉鍊的單一焦點之外,我們失去了到處傳播的所有信息。正確的duplicate在上下文中的每個位置都有一個「拉鍊」,它在該位置和該位置的上下文中保存該值。

讓我們看看我們可以從這些法則中推論出什麼。用一個小手揮動功能類別,我們可以看到=<= extractfmap extract . duplicate,這需要是身份函數。顯然,我重新發現瞭如何在Control.Category的文檔中編寫法律。這讓我們寫類似

z = (=<= extract)    z 
z = fmap extract . duplicate $ z 

現在,z只有一個構造函數,所以我們可以替換,在

Z left x right = fmap extract . duplicate $ Z left x right 

從他們輸入重複的,我們知道它必須返回相同的構造。

Z left x right = fmap extract $ Z lefts (Z l x' r) rights 

如果我們將fmap這個Z我們

Z left x right = Z (fmap extract lefts) (extract (Z l x' r)) (fmap extract rights) 

如果我們分手這件事由Z構造的部分,我們有三個方程

left = fmap extract lefts 
x = extract (Z l x' r) 
right = fmap extract rights 

這就告訴我們,至少duplicate (Z left x right)的結果必須成立:

  • 具有相同長度的左側的列表作爲left
  • 在中間x一個Z用於與相同的長度right用於右側
中間
  • 列表

    此外,我們可以看到左側和右側列表中的中間值必須與那些列表中的原始值相同。考慮到這一條法則,我們足夠了解duplicate的結果要求不同的結構。

  • +0

    嗨,Cirdec,你釘了它。我試圖自己想出一個反例,但我總是瞄準重點,我從來沒有試圖查詢上下文(就像你的'isFirst'那樣)。這不僅是正確的答案,而且還包含有關該主題的更多有用信息。 Upvoting和標記爲已接受的答案。 – Jackie 2014-12-05 09:53:17