Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

hierarchical data types

Tags:

haskell

I would like to define data types hierarchically, such as:

data Cat = BigCat | SmallCat
data Animal = Cat | Dog

And then write a function that will take Animals as arguments, and write it with pattern matching like this:

bigger::Animal -> Animal -> Bool
bigger SmallCat BigCat = False
bigger BigCat SmallCat = True
bigger Dog Cat = True
bigger Cat Dog = False

The compiler complains. It doesn't want to match the type Animal explicitely written in the function signature against the type Cat in the first and second lines of pattern matching. Why won't haskell admit that a big cat or small cat is an animal?

like image 385
Guillaume Chérel Avatar asked Dec 02 '11 17:12

Guillaume Chérel


People also ask

What are the 4 levels in data hierarchy?

Computer Data Hierarchy: Bits, Characters, fields, records, files, database bigdata.

What is example of hierarchical data structure?

Tree is an example of hierarchical data structure.

Which is a hierarchical database?

A hierarchical database is a data model in which data is stored in the form of records and organized into a tree-like structure, or parent-child structure, in which one parent node can have many child nodes connected through links.


2 Answers

You mix up types with their constructors. A type is something of which you can create variables. A type constructor is what you use to create such data. In you code, data Animal = Cat | Dog declares a type Animal with the two constructors Cat and Dog. In the other line, you define a datatype Cat. This is no problem since types and constructors don't share the same namespace.

If you want to have an object of type Cat embedded in your Animal (if the constructor Cat is used), you can add a field to the constructor:

data Animal = Cat Cat | Dog

This means: "Animal is a type that has two constructors, Cat and Dog. Cat has a field of type Cat and Dog has none." If you want to create objects with the constructor Cat, you have to pass an object of type Cat to it:

myCat = Cat BigCat

If you want to match on an Animal, you have to list all fields of the matched constructor. Compare a corrected version of your code:

data Cat = BigCat | SmallCat
data Animal = Cat Cat | Dog

bigger :: Animal -> Animal -> Bool
bigger (Cat SmallCat) (Cat BigCat)   = False
bigger (Cat BigCat)   (Cat SmallCat) = True
bigger Dog            (Cat _)        = True
bigger (Cat _)         Dog           = False

The _ denotes a don't care - regardless of the object passed, this will always match.

like image 152
fuz Avatar answered Sep 28 '22 15:09

fuz


The immediate error here is that Animal is defining two data constructors, which have nothing to do with Cat: The expression Cat is of type Animal, while the expression BigCat is of type Cat.

To create nested data types in simple fashion, you'd need to make the Cat type an argument to the relevant constructor:

data Cat = BigCat | SmallCat
data Animal = Cat Cat | Dog

You can then do something like this:

bigger (Cat SmallCat) (Cat BigCat) = False
bigger (Cat BigCat) (Cat SmallCat) = True
bigger Dog (Cat _) = True
bigger (Cat _) Dog = False

This becomes exceeding clumsy if extended beyond a trivial example, however, the redundancy in the Cat type is painful, and the two different uses of the identifier Cat is needlessly confusing. A slight improvement is to avoid conflating size with species, and instead do something like this:

data Size = Big | Small
data Species = Cat | Dog
data Animal = Animal Species Size

An advantage here is that you can more easily extend either types without having to add as much boilerplate nonsense as would otherwise be required.

However, both of these are very silly as anything other than toy examples and in actual use there's very likely to be a much better approach that would be preferable. If the types really are simple enumerations more meaningful than cats and dogs, then deriving Ord, Enum, &c. is preferable to special-purpose stuff. If the intent is a more open-ended way of modelling entities with various properties, it's worth thinking about other designs more tailored to the actual problem.

like image 42
C. A. McCann Avatar answered Sep 28 '22 15:09

C. A. McCann