2014-12-03 5 views
14

Warum, wenn Sie die Funktion Comonad doppelte Funktion

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

für die Comonad typeclass duplizieren definieren (link) Sie alle Elemente „im Kontext“ ändern (dh andere Elemente als der Strom ändern Wert des Kontexts). Warum nicht einfach etwas wie Return in einem Monad verwenden?

Beispiel (RV):

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

warum kann nicht einfach definiere ich doppelt als

duplicate z = Z [] z []  

ich für die eine Forderung abzuleiten versuchte Funktion aus den Comonad Regeln duplizieren, aber ich habe immer am Ende mit einem Duplikat, das nur das Element wie ein Rückkehr in einer Monade wickelt, ohne etwas anderes zu tun.

One blog post sagt:

Duplikat ein bisschen schwerer zu fassen ist. Aus einem Listen-Zipper müssen wir einen Listen-Zipper von Listen-Zippern erstellen. Die Bedeutung hinter dieser (durch die comonad Gesetze bestätigt, dass jede Instanz zu erfüllen hat) ist, dass innerhalb der duplizierte Struktur bewegt die ursprüngliche Struktur zurückgibt, durch die gleiche Bewegung verändert

Aber ich verstehe nicht, warum es sein muss, dieser Weg. Die fmap in den Comonad Regeln bezieht sich immer auf dem umhüllten Element und danach dieses Element ist immer „ausgepackt“ mit Extrakt, warum sonst etwas zu tun, die Mühe in die andere Funktion duplizieren als nur das Argument der Einwickeln duplizieren ?

Können Sie darauf hinweisen, was ich verpasst habe? Ich habe das Gefühl, irgendwo einen offensichtlichen Fehler gemacht zu haben, aber ich kann es mir selbst nicht erklären.

Vielen Dank im Voraus für Sie Antworten!

+0

Sie könnten diese Frage zum Ableiten von comonad-Instanzen für Reißverschlüsse generisch für jeden differenzierbaren Typ interessieren. http://stackoverflow.com/q/25554062/414413 Wenn ja, überprüfen Sie die umfangreiche Lösung des Schweinarbeiters mit partiellen Differentialgleichungen oder meine Lösung mit einer zweiten Ableitung. – Cirdec

+0

Danke für den Link, ich habe darüber gescrollt, als ich versucht habe, eine Antwort auf meine Frage zu finden, aber jetzt, wo du es ausdrücklich empfohlen hast, sehe ich, dass es eine Menge neuer Sachen für mich zum Nachdenken gibt. Ich werde mich definitiv darum kümmern. – Jackie

Antwort

6

Es ist wichtig, wenn Sie andere Dinge mit dem Typ als einfach extract daraus machen können. Intuitiv, wenn das einzige, was Sie tun können, ist, den Wert zu extrahieren, dann enthält der Typ nur einen Wert, also verdoppelt das Duplizieren dieses einen Wertes alles. Dies trifft im Allgemeinen nicht zu und gilt nicht für Reißverschlüsse.

Die Comonad Gesetze sind nur die Kategorie-Gesetze über Funktionen des Typs w a -> b verkleidet. Da diese aus Kategorien stammen, könnte es leichter sein, sie in Bezug auf eine Kategorie als in Bezug auf die Comonad Gesetze zu begründen. extract ist die Identität dieser Kategorie und =<= ist der Kompositionsoperator.

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

Wir wissen auch, dass extend f = fmap f . duplicate, so können wir

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

Das sieht ziemlich einfach, an die Vernunft schreiben.Jetzt rüsten wir Ihren Typ Z mit einer anderen Funktion aus, über die wir sprechen können. isFirst gibt nur dann true zurück, wenn Z einen Wert an einer Position in einer Liste mit nichts davor darstellt. Jetzt

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

, lassen Sie uns überlegen, was passiert, wenn wir isFirst mit den drei Kategorie Gesetze verwenden. Die einzigen zwei, die es scheint, sind unmittelbar darauf anwendbar, dass extract eine linke und rechte Identität für die Zusammensetzung von =<= ist. Da wir das nur widerlegen, brauchen wir nur ein Gegenbeispiel zu finden. Ich vermute, dass einer von extract =<= isFirst oder isFirst =<= extract für den Eingang Z [1] 2 [] ausfallen wird. Beide sollten gleich sein wie isFirst $ Z [1] 2 [], was False ist. Wir versuchen zuerst extract =<= isFirst, was passiert.

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 

Wenn wir isFirst =<= extract versuchen wir nicht so viel Glück.

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 

Wenn wir duplicate d verloren wir Informationen über die Struktur. In der Tat verloren wir Informationen über alles, was überall kam außer dem einzigen Schwerpunkt des Reißverschlusses. Die korrekte duplicate würde einen ganzen 'nother Zipper überall im Kontext haben, der den Wert an dieser Position und den Kontext dieses Standorts hält.

Mal sehen, was wir aus diesen Gesetzen ableiten können. Mit einer kleinen Hand, die über die Kategorie von Funktionen winkt, können wir sehen, dass =<= extractfmap extract . duplicate ist, und dies muss die Identitätsfunktion sein. Anscheinend entdecke ich wieder, wie die Gesetze in der Dokumentation für Control.Category geschrieben sind. Auf diese Weise können wir so etwas wie

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

Jetzt schreiben, z hat nur einen Konstruktor, so können wir ersetzen, dass in

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

Von sie von doppelten geben, wissen wir, es muss den gleichen Konstruktor zurück.

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

Wenn wir fmap dieser Z gelten haben wir

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

Wenn wir dies durch die Teile des Z Konstruktor aufgeteilt haben wir drei Gleichungen

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

Dies sagt uns, dass mindestens das Ergebnis von duplicate (Z left x right) muss halten:

  • eine Liste mit der gleichen Länge wie left für die linke Seite
  • ein Z mit x in der Mitte für die Mitte
  • einer Liste mit der gleichen Länge wie right für die rechte Seite

Außerdem können wir sehen, dass die mittleren Werte in den Listen auf der linken und rechten Seite die gleichen wie die ursprünglichen Werte in diesen Listen sein müssen.Wenn wir nur dieses eine Gesetz betrachten, wissen wir genug, um eine andere Struktur für das Ergebnis von duplicate zu verlangen.

+0

Hallo Cirdec, du hast es genagelt. Ich habe selbst versucht, ein Gegenbeispiel zu entwickeln, aber ich zielte immer auf den Brennpunkt, und ich habe nie versucht, den Kontext abzufragen (wie es dein 'isFirst' tut). Dies ist nicht nur die richtige Antwort, sondern enthält auch weitere nützliche Informationen zum Thema. Upvoting und Markierung als akzeptierte Antwort. – Jackie