2013-08-24 3 views
20

Alles, was ich weiß, ist, dass das eine funktioniert und das andere nicht.Was ist der Unterschied zwischen `ix` und` at` in der Objektivbibliothek von Haskell

Kontext: Ich habe eine Datenstruktur, die FS eine Data.Map.Map k S auf eine andere Datenstruktur enthält. Mein Ziel war es, eine Lens zu bauen, die bei F und k ein Feld in S beschreiben würde.

Die Schwierigkeit besteht darin, dass der Schlüssel k möglicherweise nicht in der Karte vorhanden ist. Das ist in Ordnung, die Funktion kann ihre Rückkehr in Maybe wickeln. Allerdings konnte ich ein Objektiv nicht durch ein Maybe mit at propagieren. Nachdem ich viele Stack Overflow Antworten gelesen hatte, stieß ich auf this one.

Es stellt sich heraus, dass at mit ix ersetzt meine Art Probleme gelöst wenn ich auch (^.) mit (^?) ersetzt.

Frage: Es scheint wie at und ix das gleiche tun, zumindest in Bezug auf Map. Beide nehmen einen Schlüssel und geben dem Wert an dieser Taste eine 'Linse'. Allerdings scheint ix mit dem Funktionszusammensetzungsoperator (.) nett zu spielen. Was ist der Unterschied zwischen den beiden?


Off Topic Rant:

Ich mag Infixoperatoren so viel wie der nächste Kerl, aber das Control.Lens Paket scheint über Bord ein wenig gegangen zu sein. Für einen neuen Benutzer mit einigen englischen Namen und einem Schlüssel irgendwo würde die Lernkurve senken. Aufgrund der großen Anzahl von Wrapper-Klassen, die in der Lens-Bibliothek verwendet werden, ist es besonders schwierig, die Typ-Signaturen zu durchsuchen, wenn Sie nicht bereits wissen, was vor sich geht. Mein Code fängt an, wie Perl um Himmels Willen zu aussehen.

+0

Sie können mit 'lens' ohne einen einzigen Infixoperator. Fast jeder Operator ist nur ein praktischer Alias ​​für einen Nicht-Operator-Namen - Sie müssen ihn nicht verwenden (und ich tue es oft nicht). – shachaf

+2

Was Sie nicht tun können, ist zu versuchen, einen Code zu verstehen, den andere geschrieben haben, sagen wir, den Beispielordner für Bibliotheken. Der Prozess, in GHCi etwas Code zu kopieren und darauf zu schlagen, ist in Lens wesentlich schwieriger als in den meisten anderen Bibliotheken. –

+0

@Shachaf das ist nicht wahr: einige sehr nützliche Operatoren existieren nicht als Wörter, nämlich '% =' (nicht so schlecht, da es in 'do' Blöcken verwendet wird) und'? ~ '(Ziemlich schlecht, da es wirklich rein ist Code, der den Wechsel von '$' zu '&' erfordert, wenn Sie keine Parens laden wollen. – spopejoy

Antwort

19

Das at und ix unterschiedlich sind bereits spürbar, wenn man sich die verfügbaren Instanzen für die Klassen aussehen, welche diese Funktionen:

  • Instanzen At: Karte, IntMap, HashMap
  • Instanzen Ixed: [ a], Karte, ByteString, Text und viel mehr

alle Instanzen, wenn At auch eine Instanz von Ix sind, aber nicht alle i nstances von Ix sind auch eine Instanz von At.

Was ist der Unterschied zwischen ihnen? At ist für Container, die das Einfügen von Schlüsseln ermöglichen, die nicht im Container vorhanden sind. Dies ist offensichtlich für eine Karte möglich, aber nicht z.B. für eine Liste. Um immer noch in der Lage zu sein, in eine Liste zu indizieren und Gegenstände zu ändern, erlaubt Ix nicht das Erstellen neuer Gegenstände, sondern "tut nichts", wenn Sie versuchen, auf einen Schlüssel zu schreiben, der nicht dort ist.

>>> Data.Map.fromList [('a', 1)] & at 'b' .~ Just 4 
fromList [('a',1),('b',4)] -- Inserts value 
>>> Data.Map.fromList [('a', 1)] & ix 'b' .~ 4 
fromList [('a',1)]   -- Does nothing because key is not present 

(Es gibt auch eine Verknüpfung für a .~ Just b, a ?~ b)

Technisch Dieser Unterschied kommt von der Tatsache, dass ix ist ein Traversal während at a Lens ist. Und weil at ein Objektiv ist, das ein Maybe Something "zurückgibt", können Sie es nicht mit einem Objektiv komponieren, das nur ein einfaches "Etwas" braucht. ix ist ein Traversal mit 0 oder 1 Werten, so dass Sie ix genau wie jedes andere Traversal schreiben können (genau wie Sie schreiben können traverse . traverse). (^?) nimmt nur den ersten Wert (Kopf) dieser Traversierung.

Sie können immer ableiten ix von at:

ixAt = at . traverse 

Die gleiche Definition is already in lens, außer es (<.) für Zusammensetzung verwendet ist, den Index zu verhindern, an. (at und ix sind beide indizierte Linsen/Durchgänge).

Off-topic: Die meisten Betreiber von Objektiv auch Infix Namen haben, können Sie eine (unvollständige) Tabelle finden Sie unter: https://github.com/ekmett/lens/wiki/Operators

+2

Ich denke "ganz anders" übertreibt es - 'ix k = at k. Traverse "ist ein Gesetz, wenn beide umgesetzt werden. 'at' bietet strengere Funktionalität als' ix' (aber 'ix' ist für mehr Typen implementiert). – shachaf

+0

@shachaf Du hast Recht. Ich habe die Antwort bearbeitet. – bennofs

Verwandte Themen