Istnieją co najmniej trzy popularne biblioteki umożliwiające dostęp do pól rekordów i manipulowanie nimi. Te, które znam, to: akcesorium do danych, etykiety fc i soczewki.
Osobiście zacząłem od akcesora danych i używam ich teraz. Jednak ostatnio w haskell-cafe panowała opinia, że fclabels są lepsze.
Dlatego interesuje mnie porównanie tych trzech (a może i więcej) bibliotek.
data-structures
haskell
record
lenses
Tener
źródło
źródło
lens
pakiet ma najbogatszą funkcjonalność i dokumentację, więc jeśli nie masz nic przeciwko jego złożoności i zależnościom, to jest droga do zrobienia.Odpowiedzi:
Są co najmniej 4 biblioteki, o których wiem, że dostarczają soczewki.
Pojęcie soczewki polega na tym, że zapewnia ona coś izomorficznego
zapewniając dwie funkcje: pobierającą i ustawiającą
podlega trzem prawom:
Po pierwsze, jeśli coś włożysz, możesz to z powrotem wyciągnąć
Po drugie, otrzymanie, a następnie ustawienie nie zmienia odpowiedzi
Po trzecie, postawienie dwa razy jest tym samym, co postawienie raz, a raczej drugie postawienie wygrywa.
Zwróć uwagę, że system typów nie jest wystarczający, aby sprawdzić te przepisy za Ciebie, więc musisz się upewnić, że niezależnie od zastosowanej implementacji obiektywu.
Wiele z tych bibliotek zapewnia również kilka dodatkowych kombinatorów na górze i zwykle jakąś formę szablonów maszyn haskell do automatycznego generowania soczewek dla pól prostych typów rekordów.
Mając to na uwadze, możemy przejść do różnych implementacji:
Wdrożenia
fclabels
fclabels jest prawdopodobnie najłatwiejszym argumentem na temat bibliotek soczewek, ponieważ
a :-> b
można go bezpośrednio przełożyć na powyższy typ. Udostępnia instancję Category,(:->)
która jest przydatna, ponieważ umożliwia komponowanie soczewek. Zapewnia równieżPoint
typ bezprawia, który uogólnia pojęcie zastosowanej tutaj soczewki i pewną hydraulikę do radzenia sobie z izomorfizmami.Jedną z przeszkód w przyjęciu programu
fclabels
jest to, że główny pakiet zawiera instalację wodno-kanalizacyjną template-haskell, więc pakiet nie jest Haskell 98, a także wymaga (raczej niekontrowersyjnego)TypeOperators
rozszerzenia.akcesor danych
[Edytuj:
data-accessor
nie używa już tej reprezentacji, ale przeszedł do formy podobnej do tej zdata-lens
. Ale zachowuję ten komentarz.]Data-accessor jest nieco bardziej popularny niż
fclabels
, po części, dlatego, że jest to Haskell 98. Jednak jego wybór wewnętrznej reprezentacji sprawia, że wymiotuję trochę w ustach.Typ
T
używany do reprezentowania soczewki jest wewnętrznie definiowany jakoW związku z tym, aby
get
określić wartość soczewki, musisz podać nieokreśloną wartość dla argumentu „a”! Wydaje mi się to niesamowicie brzydką implementacją ad hoc.To powiedziawszy, Henning włączył hydraulikę template-haskell, aby automatycznie generować akcesory w osobnym pakiecie „ data-accessor-template ”.
Ma tę zaletę, że jest to całkiem duży zestaw pakietów, które już go wykorzystują, jest to Haskell 98 i zapewnia najważniejszą
Category
instancję, więc jeśli nie zwracasz uwagi na to, jak powstaje kiełbasa, ten pakiet jest w rzeczywistości całkiem rozsądnym wyborem .soczewki
Następnie jest pakiet soczewek , który zauważa, że soczewka może zapewnić homomorfizm monady stanu między dwiema monadami stanu, poprzez bezpośrednie definiowanie soczewek jako takich homomorfizmów monad.
Gdyby rzeczywiście zadał sobie trud dostarczenia typu dla swoich soczewek, miałyby typ drugiego stopnia, taki jak:
W rezultacie raczej nie podoba mi się to podejście, ponieważ niepotrzebnie wyciąga cię z Haskell 98 (jeśli chcesz, aby typ dostarczał twoim soczewkom w abstrakcji) i pozbawia cię
Category
instancji soczewek, które pozwolą ci skomponuj je z.
. Implementacja wymaga również klas typu wieloparametrowego.Należy pamiętać, że wszystkie inne biblioteki obiektywów wymienione tutaj zapewniają jakiś kombinator lub mogą być użyte do zapewnienia tego samego efektu fokalizacji stanu, więc nic nie jest zyskiwane przez bezpośrednie kodowanie obiektywu w ten sposób.
Ponadto warunki poboczne podane na początku nie mają ładnego wyrażenia w tej formie. Podobnie jak w przypadku „fclabels”, zapewnia to metodę template-haskell do automatycznego generowania soczewek dla typu rekordu bezpośrednio w głównym pakiecie.
Ze względu na brak
Category
instancji, barokowe kodowanie i wymóg template-haskell w głównym pakiecie, jest to moja najmniej ulubiona implementacja.soczewka danych
[Edycja: od 1.8.0 te zostały przeniesione z pakietu comonad-transformers do data-lens]
W moim
data-lens
pakiecie są soczewki w ramach comonad Sklepu .gdzie
Rozszerzony jest to odpowiednik
Można to postrzegać jako uwzględnienie wspólnego argumentu pobierającego i ustawiającego w celu zwrócenia pary składającej się z wyniku pobrania elementu i metody ustawiającej, która wstawia nową wartość. Daje to obliczeniową korzyść, jaką „ustawiacz” tutaj można ponownie wykorzystać część pracy użytej do uzyskania wartości, co zapewnia bardziej wydajną operację „modyfikowania” niż w
fclabels
definicji, zwłaszcza gdy akcesoria są połączone łańcuchami.Istnieje również dobre teoretyczne uzasadnienie tego przedstawienia, ponieważ podzbiór wartości „soczewki”, które spełniają 3 prawa określone na początku tej odpowiedzi, to dokładnie te soczewki, dla których funkcja opakowana jest „komonadą węgla” dla comonady sklepowej . To przekształca 3 włochate prawa dla obiektywu
l
do 2 ładnie pozbawionych punktów odpowiedników:Podejście to pierwszy zauważył i opisał w Russell O'Connora
Functor
jestLens
jakApplicative
jestBiplate
: Przedstawiamy wielotarczowe i został blogu o oparciu o preprintu przez Jeremy Gibbons.Zawiera również szereg kombinatorów do ścisłej pracy z soczewkami i niektóre standardowe soczewki do pojemników, takie jak
Data.Map
.Tak więc soczewki w
data-lens
formie aCategory
(w przeciwieństwie dolenses
opakowania) są Haskell 98 (w przeciwieństwie dofclabels
/lenses
), są rozsądne (w przeciwieństwie do tylnej częścidata-accessor
) i zapewniają nieco bardziej wydajną implementację,data-lens-fd
zapewniają funkcjonalność do pracy z MonadState dla tych, którzy chcą wyjść na zewnątrz Haskell 98, a maszyneria template-haskell jest teraz dostępna za pośrednictwemdata-lens-template
.Aktualizacja 28.06.2012: Inne strategie wdrażania obiektywów
Soczewki izomorficzne
Warto wziąć pod uwagę dwa inne kodowania obiektywów. Pierwsza daje dobry teoretyczny sposób spojrzenia na soczewkę jako sposób na rozbicie struktury na wartość pola i „wszystko inne”.
Podano typ izomorfizmów
takie, które spełniają ważni członkowie
hither . yon = id
, iyon . hither = id
Możemy przedstawić soczewkę z:
Są one przede wszystkim przydatne jako sposób myślenia o znaczeniu soczewek i możemy ich użyć jako narzędzia do rozumowania, aby wyjaśnić inne soczewki.
Soczewki van Laarhoven
Możemy modelować soczewki w taki sposób, aby można je było komponować z,
(.)
aid
nawet bezCategory
instancji za pomocąjako typ naszych soczewek.
W takim razie zdefiniowanie soczewki jest tak proste, jak:
i możesz samodzielnie przekonać się, że skład funkcji to skład soczewki.
Niedawno pisałem o tym, jak można dalej uogólniać soczewki van Laarhovena, aby uzyskać rodziny soczewek, które mogą zmieniać typy pól, po prostu uogólniając ten podpis na
Ma to niefortunną konsekwencję, że najlepszym sposobem mówienia o soczewkach jest użycie polimorfizmu rangi 2, ale nie musisz używać tego podpisu bezpośrednio podczas definiowania soczewek.
Lens
Zdefiniowałem powyżej_2
jest faktycznieLensFamily
.Napisałem bibliotekę zawierającą soczewki, rodziny soczewek i inne uogólnienia, w tym gettery, setery, fałdy i przejścia. Jest dostępny na hackage jako
lens
pakiet.Ponownie, wielką zaletą tego podejścia jest to, że opiekunowie bibliotek mogą faktycznie tworzyć soczewki w tym stylu w twoich bibliotekach bez ponoszenia jakiejkolwiek zależności od biblioteki soczewek, po prostu dostarczając funkcjom typ
Functor f => (b -> f b) -> a -> f a
, dla ich poszczególnych typów „a” i „b”. To znacznie obniża koszt adopcji.Ponieważ nie musisz faktycznie używać pakietu do definiowania nowych obiektywów, znacznie odciąża to moje wcześniejsze obawy dotyczące zachowania biblioteki Haskell 98.
źródło
:->
data-accessor
, a potem przekazałem go Henningowi i przestałem zwracać na to uwagę.a -> r -> (a,r)
Reprezentacja również sprawia mi nieswojo, a moja oryginalna realizacja była jak twójLens
typ. Heeennnninngg !!