El error inmediata aquí es que Animal
es la definición de dos constructores de datos, que no tienen nada que ver con Cat
: La expresión es de tipo Cat
Animal
, mientras que la expresión es de tipo BigCat
Cat
.
Para crear tipos de datos anidadas en forma simple, que había necesidad de hacer que el tipo Cat
un argumento para el constructor relevante:
data Cat = BigCat | SmallCat
data Animal = Cat Cat | Dog
entonces usted puede hacer algo como esto:
bigger (Cat SmallCat) (Cat BigCat) = False
bigger (Cat BigCat) (Cat SmallCat) = True
bigger Dog (Cat _) = True
bigger (Cat _) Dog = False
Esto se vuelve excesivamente torpe si se extiende más allá de un ejemplo trivial, sin embargo, la redundancia en el tipo Cat
es dolorosa, y los dos usos diferentes del identificador Cat
son innecesariamente confusos. Una ligera mejora es evitar confundir el tamaño de las especies, y en lugar de hacer algo como esto:
data Size = Big | Small
data Species = Cat | Dog
data Animal = Animal Species Size
Una ventaja aquí es que se puede extender más fácilmente cualquiera de los tipos sin tener que agregar tanto sin sentido repetitivo que de otro modo sería necesaria .
Sin embargo, ambos son muy tontos como cualquier otro que no sean ejemplos de juguetes y en el uso real es muy probable que haya un enfoque mucho mejor que sería preferible. Si los tipos realmente son enumeraciones simples más significativas que los gatos y los perros, entonces deriving
Ord
, Enum
, & c. es preferible a cosas especiales. Si la intención es una forma más abierta de modelar entidades con varias propiedades, vale la pena pensar en otros diseños más adaptados al problema real.
"¿Por qué Haskell no admite que un gato grande o un gato pequeño es un animal?" - Porque no lo es. 'BigCat :: Cat' y' SmallCat :: Cat', pero 'Cat :: Animal'. El * constructor * 'Cat' no tiene relación con * type *' Cat'. – delnan