Кажется, что у любого ограниченного экземпляра должна быть нормальная реализация Enum. Лично я не могу придумать контрпример, хотя, если кто-то придумает такой, который не является патологическим, я пойму, почему это не так.
Из :i
этих двух классов типов кажется, что единственное исключение в стандартной библиотеке в настоящее время относится к кортежам, которые являются ограниченными, но не перечислимыми. Однако любой ограниченный кортеж также должен быть вменяемым Enumerable, просто увеличивая последний элемент, а затем оборачиваясь, когда он достигает maxBound.
Это изменение, вероятно, также будет включать добавление predB
и nextB
или что-то в этом роде в Bounded для безопасного / циклического способа обхода значений Enum. В этом случае toEnum 0 :: (...)
будет равно(toEnum 0, toEnum 0, ...) :: (...)
Double
/Float
и все подобные типы реализуются вEnum
любом случае, они просто создаютsucc = (+ 1)
иfromEnum = truncate
. Путь Haskell действительно имеет смысл с точки зрения практичности, так как в противном случае [0, 0.5 ..] и тому подобное не сработает, поэтому, похоже, Haskell не беспокоится о счетности, когда дело доходит до Enums.succ
это(+1)
. Это странно, потому чтоDouble
иFloat
не имеют бесконечную точность и , таким образом , являются перечислимы -succ
возможно, было определено как +1 ULP .Ответы:
Мне нравится один практический пример из мира языков программирования: набор типов в ОО-системе ограничен и дискретен, но не перечислим, а частично упорядочен, но не полностью упорядочен.
Рассматриваемый частичный порядок является отношением подтипов
<:
. Верхняя граница будет тогда верхним типом (который вызывает C #object
и ScalaAny
), а нижняя граница будет нижним типом (ScalaNothing
; у C # / Java нет эквивалента, о котором можно говорить).Однако нет способа перечислить все типы в системе типов, поэтому вы не можете написать
instance Enum Type
. Это должно быть понятно: пользователи могут писать свои собственные типы, поэтому нет никакого способа узнать, кем они будут заранее. Вы можете перечислить все типы в любой данной программе, но не во всей системе.Точно так же (согласно определенному разумному определению подтипа)
<:
рефлексивно, транзитивно и антисимметрично, но не полностью . Есть пары типов, которые не связаны с<:
. (Cat
иDog
оба являются подтипамиAnimal
, но ни один не является подтипом другого.)Предположим, что мы пишем компилятор для простого языка OO. Вот представление типов в нашей системе:
И определение отношения подтипа:
Это также дает нам отношение супертипирования.
Вы также можете найти наименьшую верхнюю границу двух типов,
Упражнение: покажите, что
Type
образует ограниченный полный набор в два пути, под<:
и под>:
.источник
x == y = x <= y && y <= x
. Если бы я проектировалPoset
класс, я бы имелclass Eq a => Poset a
. Быстрый Google подтверждает, что другие люди имели ту же идею .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
несопоставимы.Это потому, что операции независимы, поэтому связывание их вместе с отношениями подкласса на самом деле ничего не покупает. Скажем, вы хотели создать собственный тип, который реализован
Bounded
, возможно,Doubles
ограниченный между максимумом и минимумом, но вам не нужно было выполнять какие-либоEnum
операции. Если бы выBounded
были подклассом, вам всеEnum
равно пришлось бы реализовать все функции, просто чтобы его скомпилировать.На самом деле не имеет значения, есть ли разумная реализация
Enum
или любое другое количество классов типов. Если вам это на самом деле не нужно, вы не должны быть вынуждены это применять.Сравните это с, скажем,
Ord
иEq
. ТамOrd
операции зависят отEq
них, поэтому имеет смысл требовать подкласса, чтобы избежать дублирования и обеспечить согласованность.источник
Bounded
говорится, что «Ord не является суперклассом Bounded, поскольку типы, которые не являются полностью упорядоченными, также могут иметь верхнюю и нижнюю границы».<:
для является подтипом ,∀ T S. T <: S ∨ S <: T
не имеет места (например,int !<: bool ∧ bool !<: int
). Скорее всего, вы столкнулись бы с этим, если бы писали компилятор.