W this talk around the 1:20 mark, Edward Kmett wspomina o braku "backtrackingu klasy" w Haskell. Rozważ problem „set równości” (gdzie kolejność i wielość są pomijane) realizowany na listach:Czy istnieje obejście problemu z brakiem śledzenia klasy typu?
equals :: [a] -> [a] -> Bool
Przez charakteru zajęć typu I nie może dostarczyć nieefektywne O (n²) porównania, jeśli wszystko, co mamy jest Eq a
ale wydajnie porównaj listy w O (n log n), jeśli mamy Ord a
.
Zrozumiałem, dlaczego taki obiekt byłby problematyczny. W tym samym czasie, Edward mówi, że istnieją "sztuczki, które można grać", wspominając na przykład rodziny typu.
Stąd moje pytanie, co byłoby obejście aby osiągnąć ten sam efekt:
- An (nieskuteczny) Domyślna implementacja jest
- jeżeli użytkownik może dostarczyć dodatkowych informacji o rodzaju, my "odblokuj" bardziej wydajną implementację
To rozwiązanie nie musi koniecznie używać klas typów.
Edit: Niektórzy ludzie po prostu zaproponował dostarczenie equals
i efficientEquals
jako dwóch odrębnych metod. Ogólnie zgadzam się, że jest to bardziej podejście Haskella-idiomatyczne. Jednak nie jestem przekonany, że jest to zawsze możliwe. Na przykład, co jeśli metoda equals powyżej sama jest częścią klasy typu:
class SetLike s where
equals :: Eq a => s a -> s a -> Bool
Załóżmy, że klasa ta została przekazana przez kogoś innego, więc nie można po prostu dodać nową funkcję do typeclass. Teraz chcę zdefiniować instancję dla []
. Wiem, że []
zawsze może zapewnić implementację equals
bez względu na ograniczenia, które istnieją na a
, ale nie mogę powiedzieć, aby moja instancja używała bardziej wydajnej wersji, jeśli jest dostępna większa ilość informacji o a
.
Może mogę zawinąć listę w nowy typ i oznaczyć ją dodatkowymi informacjami o typie?
Jest to bardzo interesujące i nie znam odpowiedzi na to. Ale szybkie i brudne byłoby zdefiniowanie innej funkcji, takiej jak 'efficientEquals :: (Ord a) => [a] -> [a] -> Bool' i' equals :: (Eq a) => [a] -> [a] -> Bool'. – Shoe
Proszę wyjaśnić, że mówimy o porównywaniu list _disregarding order_ (i ewentualnie także o wielości). Oczywiście '(==)' nie wymaga O (n^2) na listach. – chi
IIRC, GHC pozwala określić '{- # RULE ... equals = efficientOrdEquals # -}', które zostanie zastosowane tylko wtedy, gdy sprawdzenia typu RHS. W ten sposób połączenia statycznie znane z typami uporządkowanymi otrzymają sprawną wersję. – chi