Il semble que toute instance Bounded devrait avoir une implémentation saine d'Enum. Je ne peux pas personnellement penser à un contre-exemple, bien que si quelqu'un en trouve un qui n'est pas pathologique, je comprendrai pourquoi ce n'est pas le cas.
En faisant :i
sur les deux classes de caractères, il semble que la seule exception actuellement dans la bibliothèque standard soit pour les tuples, qui sont délimités mais pas les énumérations. Cependant, tout tuple Bounded doit également être énumérable de manière sensée, en incrémentant simplement le dernier élément, puis en bouclant lorsqu'il atteint maxBound.
Ce changement impliquerait probablement également l'ajout predB
et / nextB
ou quelque chose comme ça à Bounded pour un moyen sûr / en boucle de parcourir les valeurs Enum. Dans ce cas, toEnum 0 :: (...)
serait égal à(toEnum 0, toEnum 0, ...) :: (...)
Double
/Float
et tous les types similaires implémentent deEnum
toute façon, ils font justesucc = (+ 1)
etfromEnum = truncate
. La façon dont Haskell a du sens d'un point de vue pratique, sinon [0, 0,5 ..] et similaire ne fonctionnerait pas, il semble donc que Haskell ne se soucie pas de la comptabilité en ce qui concerne les énumérations.succ
est(+1)
. C'est étrange, carDouble
etFloat
n'ont pas une précision infinie et sont donc énumérables -succ
aurait pu être défini comme +1 ULP .Réponses:
Un exemple pratique que j'aime vient du monde des langages de programmation: l'ensemble des types dans un système OO est borné et discret mais non énumérable, et partiellement ordonné mais pas totalement ordonné.
L'ordre partiel en question est la relation de sous-typage
<:
. La borne supérieure serait alors le type supérieur (dont C # appelleobject
et Scala appelleAny
), et la borne inférieure serait le type inférieur (ScalaNothing
; C # / Java n'ont pas d'équivalent pour parler).Cependant, il n'existe aucun moyen d'énumérer tous les types dans le système de types, vous ne pouvez donc pas écrire un
instance Enum Type
. Cela devrait être clair: les utilisateurs peuvent écrire leurs propres types, il n'y a donc aucun moyen de savoir ce qu'ils seront à l'avance. Vous pouvez énumérer tous les types dans un programme donné, mais pas dans l'ensemble du système.De même, (selon une certaine définition raisonnable du sous-typage),
<:
est réflexif, transitif et antisymétrique mais pas total . Il existe des paires de types qui ne sont pas liées par<:
. (Cat
etDog
sont tous deux des sous-types deAnimal
, mais aucun n'est un sous-type de l'autre.)Supposons que nous écrivons un compilateur pour un langage OO simple. Voici la représentation des types dans notre système:
Et la définition de la relation de sous-typage:
Cela nous donne également une relation de supertypage.
Vous pouvez également trouver la borne supérieure la moins haute de deux types,
Exercice: montrez que
Type
forme un poset complet borné de deux manières, sous<:
et sous>:
.la source
x == y = x <= y && y <= x
. Si je concevais unePoset
classe, j'en auraisclass Eq a => Poset a
. Un rapide Google confirme que d' autres personnes ont eu la même idée .data Bound a = Min | Val a | Max
qui augmente un typea
avec+∞
et les-∞
éléments. Par construction,Bound a
on peut toujours en faire une instance,Bounded
mais ce ne serait équitable que si le type sous-jacenta
estDouble
, oùconst (1/0)
estmaxBound
etconst (negate 1/0)
estminBound
mais\x -> 1 - x
et qui\x -> x - 1
sont incomparables.C'est parce que les opérations sont indépendantes, donc les lier avec une relation de sous-classe ne vous rapporte rien. Supposons que vous vouliez créer un type personnalisé qui soit implémenté
Bounded
, peut-êtreDoubles
contraint entre un max et un min, mais que vous n'aviez besoin d'aucune desEnum
opérations. SiBounded
c'était une sous-classe, il faudraitEnum
quand même implémenter toutes les fonctions, juste pour la faire compiler.Peu importe s'il existe une implémentation raisonnable pour
Enum
, ou tout autre nombre de classes de caractères. Si vous n'en avez pas réellement besoin, vous ne devriez pas être obligé de l'implémenter.Comparez cela avec, disons,
Ord
etEq
. Là, lesOrd
opérations dépendent deEq
celles-ci, il est donc logique d'exiger la sous-classe pour éviter les doublons et garantir la cohérence.la source
Bounded
indique que "Ord n'est pas une superclasse de Bounded car les types qui ne sont pas totalement ordonnés peuvent également avoir des limites supérieures et inférieures."<:
pour est un sous-type de ,∀ T S. T <: S ∨ S <: T
ne tient pas (par exemple,int !<: bool ∧ bool !<: int
). Vous rencontreriez probablement cela si vous écriviez un compilateur.