Przyjrzę się przykładowi podstawowych typów danych w uogólnionych metodach sortowania radix Fritza Hengleina, zaimplementowanych przez Edwarda Kmetta w pakiecie discrimination.
Chociaż nie wiele się tam dzieje, to w dużej mierze koncentruje się wokół typu jak ten
data Group a = Group (forall b . [(a, b)] -> [[b]])
Jeśli masz wartość typu Group a
ty zasadniczo musi mieć relację równoważności na a
bo jeśli dam ci skojarzenie między a
s i niektóre typu b
całkowicie nieznany Ci następnie możesz dać mi "grupowania" b
.
Możesz to zobaczyć jako typ rdzeniowy do pisania biblioteki narzędziowej grupowań. Na przykład, możemy chcieć wiedzieć, że jeśli możemy Group a
i Group b
, możemy Group (a, b)
(więcej o tym w sekundę). Podstawową ideą Hengleina jest to, że jeśli zaczniesz od podstawowych liczb Group
s na liczbach całkowitych - możemy pisać bardzo szybko implementacje przez sortowanie radiatryczne - a następnie użyć kombinatorów, aby rozszerzyć je na wszystkie typy, wtedy będziesz miał uogólnione sortowanie radix na algebraiczne typy danych.
Jak więc możemy zbudować naszą bibliotekę kombinatorów?
Cóż, f :: Group a -> Group b -> Group (a, b)
jest bardzo ważne, ponieważ pozwala nam tworzyć grupy typów produktów. Zwykle otrzymamy to od Applicative
i liftA2
, ale zauważysz, że to , a nie Functor
.
Zamiast więc używamy Divisible
divided :: Group a -> Group b -> Group (a, b)
Zauważ, że wynika to w dziwny sposób z
divide :: (a -> (b, c)) -> Group b -> Group c -> Group a
ponieważ ma typowy charakter „odwrócone strzałki” z kontrawariantny rzeczy. Możemy teraz zrozumieć takie rzeczy, jak divide
i conquer
pod względem ich interpretacji na Group
.
Divide mówi, że jeśli chcę zbudować strategię zrównując a
S przy zastosowaniu strategii zrównując b
s i c
s, mogę wykonać następujące czynności dla każdego typu x
Weź częściową zależność [(a, x)]
i mapuj nad nim z funkcją f :: a -> (b, c)
i małą manipulacją krotką, aby uzyskać nową relację [(b, (c, x))]
.
używać mojego Group b
dyskryminować [(b, (c, x))]
do [[(c, x)]]
Użyj mojego Group c
dyskryminować każdy [(c, x)]
do [[x]]
podając mi [[[x]]]
spłaszczyć wewnętrznych warstw, aby uzyskać [[x]]
jak musimy
instance Divisible Group where
conquer = Group $ return . fmap snd
divide k (Group l) (Group r) = Group $ \xs ->
-- a bit more cleverly done here...
l [ (b, (c, d)) | (a,d) <- xs, let (b, c) = k a] >>= r
Mamy również uzyskać interpretacje bardziej skomplikowane Decidable
refinement of Divisible
class Divisible f => Decidable f where
lose :: (a -> Void) -> f a
choose :: (a -> Either b c) -> f b -> f c -> f a
instance Decidable Group where
lose :: (a -> Void) -> Group a
choose :: (a -> Either b c) -> Group b -> Group c -> Group a
one odczytywane jako powiedzenie, że dla każdego typu a
którego możemy zagwarantować nie ma wartości (nie możemy produkować wartości Void
za pomocą wszelkich środków, funkcja a -> Void
jest sposobem wytwarzania Void
podane a
, więc nie musi być w stanie produkować wartości a
wszelkimi środkami albo!), a następnie od razu uzyskać grupowanie wartości zerowe
lose _ = Group (\_ -> [])
Możemy również przejść podobną grę jak do divide
powyżej, z wyjątkiem tego, że zamiast sekwencjonowania naszego użycia dyskryminatorów wejściowych, wykonujemy naprzemiennie.
Korzystanie z tych technik budujemy bibliotekę „Group
móc” rzeczy, a mianowicie Grouping
class Grouping a where
grouping :: Group a
i zauważ, że nearly all the definitions arise od podstawowej definicji szczycie groupingNat
który używa szybkich monadycznego manipuations wektorowej do osiągnięcia efektywny sortowanie radix.
Ed Kmett pracował nad tym, by uogólnić metody generowania radik u Fritza Hengleina. Okazuje się, że owi "dyskryminatorzy" są naturalnymi Divisibles i większość techniki może być napisana według tego typu klasy https://hackage.haskell.org/package/discrimination –
Oh wow, to imponujące. To prawie ostatnie miejsce, w którym kiedykolwiek pomyślałem by użyć klasy typu. – TheSeamau5
@ J.Abrahamson powinieneś sformułować swój komentarz w odpowiedzi, ponieważ zasługuje on na wszystkie przeboje. Zwłaszcza jeśli dołączasz próbki kodu^_^ – frasertweedale