Chociaż wiem, że istnieje rozszerzenie TypeSynonymInstances w GHC, nie mam pojęcia, jak "niebezpieczne" jest i zastanawiam się, czy to ograniczenie jest arbitralne, tak jak ograniczenie Monomorphism, lub jeśli istnieją głębsze powody dla niego.Dlaczego Haskell nie zezwala na typowe synonimy podczas deklarowania wystąpień klas?
Odpowiedz
TypeSynonymInstances
jest całkowicie bezpieczny. Ponieważ coś potencjalnie fantazyjny jak częściowo stosowanymi synonimami typu jest niedozwolone, to ma dokładnie taki sam efekt jak wpisanie się po stronie prawicy typu synonim w głowie instancji, tj
type Foo a = ([a], [a])
instance Bar (Foo a)
jest taka sama jak
instance Bar ([a], [a])
Należy jednak pamiętać, że obie instancje wymagają FlexibleInstances
, ponieważ zawierają konstruktory typów zagnieżdżonych, a także zmienne typu powtarzalnego. Zazwyczaj dzieje się tak po rozszerzeniu synonimów typu.
Myślę, że to może być powód, dla którego są one domyślnie zabronione.
Jednak jest również całkowicie bezpiecznym przedłużeniem. Najgorsze może zrobić to spowodować błąd kompilacji, jeśli starają się określić nakładających się przypadki takie jak
instance Xyzzy String
instance Xyzzy [a]
Jak, dlaczego FlexibleInstances
nie jest dostępna domyślnie, mogę się tylko domyślać, że to uproszczenie języka. Standardowe reguły dla nagłówków instancji zapewniają, że jedyne możliwe definicje instancji sposobu mogą się pokrywać, jeśli konstruktory typów w głowicach instancji są identyczne, a sprawdzanie pokrywania się jest nieco trudniejsze niż w przypadku FlexibleInstances
.
Jak rozumiem, jest to coś w rodzaju ograniczenia monomorfizmu - nie ma nic złego w pozbyciu się tego, ale otwiera cię na zachowanie, którego możesz nie oczekiwać. Tak jak monomorfizm, ograniczenie nie niszczy niczego - wszystkie te typy są nadal ważne - to również powinno być całkowicie bezpieczne: istnieją ograniczenia co do synonimów typu, które i tak nie pozwalają im na nic bardziej przyjemnego niż zwykłe skrócenie nazwy (, np., ty nigdy nie mogą ich częściowo zastosować, więc nie otrzymujemy lambd z poziomu typu), więc zawsze można je zastąpić prawą stroną ich definicji. W związku z tym, ponieważ prawe strony tych definicji mogą być sprawdzane jako nagłówki instancji (lub zawierają dodatkowe synonimy do rozwinięcia), nic nie powinno być niebezpieczne.
Z drugiej strony, podobnie jak wyłączenie ograniczenia monomorfizmu otwierają się potencjalnie dziwne charakterystyki wydajności, włączenie instancji synonimów typu otwiera się na błędy klasy potencjalnie nieparzystej. Warto więc włączyć -XTypeSynonymInstances
i spróbuj pisząc wystąpienie z synonim typu:
Prelude> :set -XTypeSynonymInstances
Prelude> instance Num String where (+) = (++)
<interactive>:3:10:
Illegal instance declaration for `Num String'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Num String'
String
wygląda jak zwykły starego typu, więc może to być zaskakujące na pierwszy; ale tak naprawdę jest to [Char]
, więc ta instancja jest nieważna zgodnie ze ścisłymi regułami Haskell 2010.Jeśli odpoczywamy tych zasad obracając kolej na -XFlexibleInstances
(który, nawiasem mówiąc, implies -XTypeSynonymInstances
), ten przykład działa teraz:
Prelude> :set -XFlexibleInstances
Prelude> instance Num String where (+) = (++)
... errors about undefined methods ...
Prelude> "a" + "b"
"ab"
Ale sytuacja staje się brzydka szybko:
Prelude> instance Eq String where
Prelude> "a" == "b"
<interactive>:8:5:
Overlapping instances for Eq [Char]
arising from a use of `=='
Matching instances:
instance Eq a => Eq [a] -- Defined in `GHC.Classes'
instance Eq String -- Defined at <interactive>:7:10
In the expression: "a" == "b"
In an equation for `it': it = "a" == "b"
Ponownie, choć String
wygląda odrębny typ, mamy już instancję dla [a]
, a więc nakłada się z nią. (I w rzeczywistości jest to prawdopodobnie powodem, dla którego -XFlexibleInstances
nie jest domyślnie włączony). Włączenie -XOverlappingInstances
to a much dodgier idea niż włączenie -XFlexibleInstances
.
Kiedyś było dozwolone, ale próbując sprawić, by Haskell był mniej pełen niespodzianek dla początkujących, został zbanowany.
- 1. Dlaczego szablon Haskell zezwala na dowolne operacje IO podczas kompilacji?
- 2. Dlaczego CGSize nie używa * podczas deklarowania zmiennych?
- 3. Rozszerzanie klas i wystąpień
- 4. błąd podczas deklarowania funkcji lambda: zadeklarować pierwszy
- 5. Typowe generyczne aktualizacje klas przypadków w Scali
- 6. Dlaczego Java nie zezwala na przeciążenia na podstawie parametrów typu?
- 7. Dlaczego funkcja Task.Delay() zezwala na nieskończone opóźnienie?
- 8. Idiomatyczny sposób deklarowania klas niezmiennych C++
- 9. C90 nie zezwala na użycie% lf w printf, dlaczego?
- 10. Dlaczego Hashtable nie zezwala na puste klucze lub wartości?
- 11. Dlaczego muszę powtarzać podprogram sortowania podczas deklarowania std :: set?
- 12. Dlaczego C# nie zezwala na dziedziczenie typu zwrotu podczas implementowania interfejsu
- 13. Sposób na wyodrębnienie Google Synonimy
- 14. MongoDB nie zezwala na używanie "." w kluczu
- 15. Dlaczego nie ma błędu podczas przekazywania argumentów linii poleceń podczas deklarowania głównego jako `int main (void)`?
- 16. Dlaczego TypeSynonymInstances nie zezwala na stosowanie częściowo używanych synonimów w nagłówkach instancji?
- 17. Dlaczego sed nie zastępuje wszystkich wystąpień?
- 18. KeyUsage nie zezwala na podpisy cyfrowe
- 19. Sprawdzone metody Haskell QuickCheck (szczególnie podczas testowania klas typów)
- 20. QTableView - nie zezwala użytkownikowi na edycję komórki
- 21. Django @override_settings nie zezwala na słownik?
- 22. sqlbulkcopy - nie zezwala na wartość DBNull.Value.?
- 23. Dlaczego nie można umieścić sygnatury typu w deklaracji wystąpień w Haskell?
- 24. Synonimy za pomocą Lucene
- 25. Jak pominąć typowe klasy w VS 2008 podczas wchodzenia?
- 26. Dlaczego te typowe operacje na kolekcjach zostały zmienione w Julia?
- 27. Użyj pola local.properties podczas deklarowania pliku buildConfigField
- 28. Dlaczego C++ pozwala na otaczanie nazwy zmiennej w nawiasach podczas deklarowania zmiennej?
- 29. Dlaczego perfmon nie może zobaczyć wystąpień mojego niestandardowego licznika wydajności?
- 30. Dlaczego platforma Haskell nie instaluje się na OS X?