Wygląda na to, że każda instancja Bounded powinna mieć rozsądną implementację Enum. Nie mogę osobiście wymyślić kontrprzykładu, chociaż jeśli ktoś wymyśli taki, który nie jest patologiczny, zrozumiem, dlaczego tak nie jest.
Z robienia :i
na dwóch typach klas wydaje się, że jedynym wyjątkiem obecnie w standardowej bibliotece są krotki, które są ograniczone, ale nie wyliczają. Jednak każda krotka Bounded musi być również wyliczalna w rozsądny sposób, po prostu zwiększając ostatni element, a następnie zawijając, gdy dojdzie do maxBound.
Ta zmiana prawdopodobnie wymagałaby również dodania predB
i / nextB
lub czegoś takiego do Bounded w celu bezpiecznego / zapętlonego sposobu przechodzenia przez wartości Enum. W takim przypadku toEnum 0 :: (...)
byłoby równe(toEnum 0, toEnum 0, ...) :: (...)
Double
/Float
i wszystkie podobne typy iEnum
tak implementują , po prostu tworząsucc = (+ 1)
ifromEnum = truncate
. Sposób Haskella ma sens z praktycznego punktu widzenia, ponieważ w przeciwnym razie [0, 0,5 ..] i podobne nie działałyby, więc wydaje się, że Haskell nie martwi się o policzalność, jeśli chodzi o Enums.succ
jest(+1)
. To dziwne, ponieważDouble
iFloat
nie mają nieskończonej precyzji, a zatem są policzalne -succ
można by je zdefiniować jako +1 ULP .Odpowiedzi:
Jeden praktyczny przykład, który mi się podoba, pochodzi ze świata języków programowania: zestaw typów w systemie OO jest ograniczony i dyskretny, ale nie można go wyliczyć i częściowo uporządkować, ale nie uporządkować całkowicie.
Przedmiotowe częściowe uporządkowanie jest relacją podtypu
<:
. Górna granica byłaby wówczas rodzajem górnym (które wywołuje C #object
i wywołania ScaliAny
), a dolna granica byłaby typem dolnym (ScalaNothing
; C # / Java nie ma odpowiednika, o którym można mówić).Jednak nie ma sposobu na wyliczenie wszystkich typów w systemie typów, więc nie można napisać an
instance Enum Type
. Powinno to być jasne: użytkownicy mogą pisać własne typy, więc nie ma sposobu, aby wiedzieć, co będą z góry. Możesz wyliczyć wszystkie typy w dowolnym programie, ale nie w całym systemie.Podobnie (zgodnie z pewną rozsądną definicją podtypu)
<:
jest zwrotny, przechodni i antysymetryczny, ale nie całkowity . Istnieją pary typów, które nie są powiązane<:
. (Cat
iDog
oba są podtypamiAnimal
, ale żaden z nich nie jest podtypem drugiego).Załóżmy, że piszemy kompilator dla prostego języka OO. Oto reprezentacja typów w naszym systemie:
I definicja relacji podtypu:
Daje nam to również relację nadrzędności.
Możesz także znaleźć najmniejszą górną granicę dwóch typów,
Ćwiczenie: pokaż, że
Type
tworzy pełny kompletny zbiór na dwa sposoby, pod<:
i pod>:
.źródło
x == y = x <= y && y <= x
. Gdybym projektowałPoset
klasę, miałbymclass Eq a => Poset a
. Szybkie Google potwierdza, że inne osoby miały ten sam pomysł .data Bound a = Min | Val a | Max
, które wzmacnia typa
z+∞
i-∞
elementy. Z konstrukcjiBound a
można zawsze zrobić przykład,Bounded
ale byłoby to możliwe tylko wtedy, gdy typem podstawowyma
jestDouble
, gdzieconst (1/0)
jestmaxBound
iconst (negate 1/0)
jest,minBound
ale są\x -> 1 - x
i\x -> x - 1
są nieporównywalne.Wynika to z faktu, że operacje są niezależne, więc powiązanie ich z relacją podklasy tak naprawdę niczego nie kupi. Załóżmy, że chcesz utworzyć niestandardowy typ, który został zaimplementowany
Bounded
, być możeDoubles
ograniczony między wartością maksymalną a minimalną, ale żadna zEnum
operacji nie była konieczna . GdybyBounded
była podklasą, i tak musiałbyś zaimplementować wszystkieEnum
funkcje, żeby ją skompilować.Tak naprawdę nie ma znaczenia, czy istnieje rozsądna implementacja
Enum
lub jakakolwiek inna liczba klas. Jeśli tak naprawdę go nie potrzebujesz, nie powinieneś być zmuszany do jego wdrożenia.Porównaj to z powiedzmy
Ord
iEq
. TamOrd
operacje są zależne odEq
tych, więc sensowne jest wymaganie podklasy, aby uniknąć powielania i zapewnić spójność.źródło
Bounded
mówi, że „ Zamówienie nie jest nadklasą Bounded, ponieważ typy, które nie są całkowicie uporządkowane, mogą mieć także górne i dolne granice”.<:
dla jest podtypem ,∀ T S. T <: S ∨ S <: T
nie ma (npint !<: bool ∧ bool !<: int
.). Prawdopodobnie byś na to wpadł, gdybyś pisał kompilator.