Чому не обмежений підклас Енума в Хаскеллі


9

Схоже, що будь-який обмежений екземпляр повинен мати розумну реалізацію Enum. Я особисто не можу придумати контрприклад, хоча якщо хтось придумає той, який не є патологічним, то я зрозумію, чому це не так.

З того, що робити :iна двох класах типових класів, здається, єдиним винятком, який зараз є у стандартній бібліотеці, є кортежі, які є Bounded, але не Enums. Однак будь-який обмежений кортеж також повинен бути численним у розумному вигляді, просто збільшуючи останній елемент, а потім обертаючись, коли він дістається до maxBound.

Ця зміна, ймовірно, також передбачає додавання predBта nextBчимось подібне до Обмеженого для безпечного / циклічного способу проходу через значення Enum. У цьому випадку toEnum 0 :: (...)було б дорівнює(toEnum 0, toEnum 0, ...) :: (...)


3
Не можу реально відповісти на це авторитетно, але врахуйте діапазон усіх реальних чисел від 0 до 1. Він має чітку нижню та верхню межі, але має незліченно нескінченні члени.
Доваль

@Doval, це справедлива точка. Однак те ж саме можна сказати про всі реальні числа в цілому (незліченно нескінченні члени), але Double/ Floatі всі подібні типи впроваджують Enumвсе одно, вони просто роблять succ = (+ 1)і fromEnum = truncate. Шлях Haskell насправді має сенс з точки зору практичності, оскільки в іншому випадку [0, 0,5 ..] і подібні не спрацювали, тому, схоже, Haskell не переживає про підрахунок, коли мова йде про Enums.
крапка з комою

1
Я не знав, що succце (+1). Це дивно, тому що Doubleі Floatне мають нескінченну точність і , таким чином , є перелічуваних - succможливо, було визначено як +1 ULP .
Доваль

2
@Doval Я думаю, що причина цього полягала в тому, що основна команда Haskell хотіла [1 ..] означати те саме, що і з парними, що це означає з Ints.
крапка з комою

@semicolon парні і плавці не є реальними числами (наприклад, не можна зберігати PI в подвійному, не втрачаючи певної точності), тому вони перелічені
jk.

Відповіді:


8

Один практичний приклад, який мені подобається, походить із світу мов програмування: набір типів в системі ОО обмежений і дискретний, але не перелічений, частково впорядкований, але не повністю упорядкований.

Про часткове впорядкування, про яке йде мова, є відношення підтипу <:. Верхня межа буде тоді верхнім типом (який викликає C # objectта Scala Any), а нижньою є нижня ( типом Scala Nothing; C # / Java не може бути еквівалентним).

Однак немає можливості перерахувати всі типи в системі типів, тому ви не можете написати an instance Enum Type. Це повинно бути зрозуміло: користувачі можуть писати власні типи, тому немає можливості знати заздалегідь. Ви можете перерахувати всі типи в будь-якій заданій програмі, але не у всій системі.

Так само (за певним розумним визначенням підтипу), <:є рефлексивним, транзитивним та антисиметричним, але не повним . Є пари типів, які не пов'язані між собою <:. ( Catі Dogє обома підтипами Animal, але жоден підтип іншого не є.)


Припустимо, ми пишемо компілятор для простої мови ОО. Ось представлення типів у нашій системі:

data Type = Bottom | Class { name :: String, parent :: Type } | Top

І визначення відношення підтипу:

(<:) :: Type -> Type -> Bool
Bottom <: _ = True
Class _ _ <: Bottom = False
Class n t <: s@(Class m _)
    | n == m = True  -- you can't have different classes with the same name in this hypothetical language
    | otherwise = t <: s  -- try to find s in the parents of this class
Class _ _ <: Top = True
Top <: Top = True
Top <: _ = False

Це також дає нам відношення власності.

(>:) :: Type -> Type -> Bool
t >: s = s <: t

Ви також можете знайти найменшу верхню межу двох типів,

lub :: Type -> Type -> Type
lub Bottom s = s
lub t Bottom = t
lub t@(Class _ p) s@(Class _ q) =
    | t >: s = t
    | t <: s = s
    | p >: s = p
    | t <: q = q
    | otherwise = lub p q
lub Top _ = Top
lub _ Top = Top

Вправа: покажіть, що Typeутворює обмежений повний набір двома способами, під <:і під >:.


Дивовижне дякую! Це відповідає на моє запитання повністю, а також відповідає на моє подальше запитання про Орда. Чи будуть у Eq подібні проблеми? Якщо нееквівалентний тип може мати maxBound або minBound. У цьому випадку Cat == Dog просто повертає помилкові, оскільки вони є різними класами, чи це було б не визначити через те, що положення дерева не ставить ані вище, ані нижче іншого?
крапка з комою

Впорядкування передбачає рівність - просто визначте x == y = x <= y && y <= x. Якби я проектував Posetклас, я мав би class Eq a => Poset a. Швидкий Google підтверджує, що інші люди мали таку саму ідею .
Бенджамін Ходжсон

Вибачте, моє запитання було неоднозначним. То, що я мав на увазі, чи означає, що Bounded мав на увазі Eq, навіть якщо це не означає Орда.
крапка з комою

@semicolon Знову немає ніяких стосунків між двома класами. Розглянемо data Bound a = Min | Val a | Max, яка доповнює типу aз +∞і -∞елементами. За побудовою Bound aзавжди можна зробити екземпляр , Boundedале це було б тільки equatable якщо основний тип aє
Бенджамін Ходжсон

добре досить справедливо Я припускаю , що один з прикладів можуть бути функції , які приймають і повертаються значення типу Double, де const (1/0)є maxBoundі const (negate 1/0)є , minBoundале \x -> 1 - xі \x -> x - 1непорівнянні.
крапка з комою

4

Це тому, що операції є незалежними, тому зв’язування їх разом із співвідношеннями підкласу насправді нічого не купує. Скажімо, ви хочете створити користувацький тип, який реалізовується Bounded, можливо, Doublesобмежений між макс Enum. Якби це Boundedбув підклас, вам доведеться все- Enumтаки реалізовувати всі функції, лише щоб його скласти.

Не важливо, чи є розумна реалізація для Enumбудь-якої іншої кількості класів типу. Якщо вона вам насправді не потрібна, ви не повинні змушувати її впроваджувати.

Протиставляйте це скажімо, Ordі Eq. Там Ordоперації залежать від операцій Eq, тому має сенс вимагати від підкласу, щоб уникнути дублювання та забезпечити узгодженість.


1
У цих випадках це частина визначення. Усі монади є також додатками та функціонерами за визначенням, тому ви не можете виконати "контракт" монади, не виконавши інших. Я недостатньо знайомий з математикою, щоб знати, чи це фундаментальне відношення чи нав'язуване визначення, але в будь-якому випадку ми зараз з цим стикаємося.
Карл Білефельдт

6
@semicolon ДокументаціяBounded говорить: " Порядок не є суперкласом" Обмежений ", оскільки типи, які не є повністю упорядкованими, також можуть мати верхню та нижню межі."
Бенджамін Ходжсон

1
@BenjaminHodgson Навіть не думав про частково впорядковані типи. +1 для непатологічного прикладу та для цитування документації.
Доваль

1
@semicolon Прикладом часткового замовлення у комп'ютерах світу може бути підтиснення мов OO. Написання <:для - це підтип , ∀ T S. T <: S ∨ S <: Tне втримується (наприклад, int !<: bool ∧ bool !<: int). Ви, ймовірно, зіткнетеся з цим, якби писали компілятор.
Бенджамін Ходжсон

1
@BenjaminHodgson ах добре. Так, наприклад, якщо A є надкласом B і C, а D є підкласом B і C, то B і C є незрівнянними, але A і D є max / min?
крапка з комою
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.