L'errore immediato è che Animal
sta definendo due costruttori di dati, che non hanno nulla a che fare con Cat
: L'espressione Cat
è di tipo Animal
, mentre l'espressione BigCat
è di tipo Cat
.
Per creare tipi di dati nidificati in modo semplice, avresti bisogno di fare il tipo di Cat
un argomento al costruttore rilevanti:
data Cat = BigCat | SmallCat
data Animal = Cat Cat | Dog
è quindi possibile fare qualcosa del genere:
bigger (Cat SmallCat) (Cat BigCat) = False
bigger (Cat BigCat) (Cat SmallCat) = True
bigger Dog (Cat _) = True
bigger (Cat _) Dog = False
Questo diventa eccessivamente maldestro se esteso oltre un esempio banale, tuttavia, la ridondanza nel tipo Cat
è dolorosa e i due diversi usi dell'identificatore Cat
sono inutilmente confusi. Un lieve miglioramento è quello di evitare una confusione fra dimensioni, con le specie, e invece fare qualcosa del genere:
data Size = Big | Small
data Species = Cat | Dog
data Animal = Animal Species Size
Un vantaggio è che è possibile estendere più facilmente entrambi i tipi senza dover aggiungere il più boilerplate una sciocchezza come sarebbe altrimenti necessario .
Tuttavia, entrambi questi sono molto sciocchi come qualcosa di diverso da esempi di giocattoli e in uso reale è molto probabile che sia un approccio molto migliore che sarebbe preferibile. Se i tipi sono in realtà semplici enumerazioni più significative di cani e gatti, quindi deriving
Ord
, Enum
, & c. è preferibile a cose speciali. Se l'intento è un modo più aperto di modellare entità con varie proprietà, vale la pena di pensare ad altri progetti più adeguati al problema reale.
fonte
2011-12-02 17:24:50
"Perché Haskell non ammetterà che un gatto grande o un piccolo gatto è un animale?" - Perché non lo è. 'BigCat :: Cat' e' SmallCat :: Cat', ma 'Cat :: Animal'. Il costruttore * * Cat' non ha relazione con il * tipo * 'Cat'. – delnan