====== 9. Algebraic data-types (ADT) ======
A simple definition of an ADT in Haskell is:
data Shape = Rectangle Integer Integer | Circle Integer
The part ''data Shape = ...'' of a definition introduces a new type called ''Shape'' in the program. Objects of any type (including ''Shape'') are constructed **functionally** by calling special functions called **data constructors**. Our definition has **two** data constructors:
- ''Rectangle''
- ''Circle''
**Data constructors** are defined as part of the ADT definition (the right-hand size of ''=''). They are functions which take different other values (or even no value) and always return a value of the **defined ADT**. In our example, the definition:
- ''Rectangle Integer Integer'' creates the data constructor ''Rectangle :: Integer -> Integer -> Shape''
- ''Circle Integer'' creates the data constructor ''Circle :: Integer -> Shape''
We can define functions over newly-defined ADTs by using pattern matching. The **permited patterns** for an ADT are its **data constructors**. Example:
area :: Shape -> Integer
area (Rectangle x y) = x * y
area (Circle x) = 3*x*x
===== 9.1. A few simple ADTs =====
9.1.1. Create a datatype which may encode 3 different values: true, false and unknown. Implement the operation //and// over such values. (when one of //and//'s operands is unknown, it's value is unknown).
9.1.2. Create a datatype ''Nat'' which encodes **natural numbers**, following the rules:
- //zero is a special natural number//
- //each non-zero natural number is the **successor** of some natural number//
Implement the encoding conversion functions:
toInteger :: Nat -> Integer
fromInteger :: Integer -> Nat -- the integer will always be positive
9.1.3. Implement the ADT of an ID, where an ID may be defined as:
* a CNP (Personal Identification Number). In Romania, the CNP has the following structure: ''SDDMMYYXXXXXX'' where:
- ''S'' is the **gender** and **birth-period** digit:
- ''S=1'' - male born before year ''2000''
- ''S=2'' - female born before year ''2000''
- ''S=5'' - male born starting from ''2000''
- ''S=6'' - female born starting from ''2000''
- ''DDMMYY'' indicates the birth date (D-day, M-month, Y-year)
- ''XXXXXX'' - the last six digits encode other info which are not relevant for us.
or
* a collection of strings which represent:
- Full name
- Complete year of birth
- gender (''male'' or ''female'')
* Implement the type ''Gender'' (it is better to define a gender separately, instead of using True/False or strings, because it reduces the occurrence of bugs).
* Implement a function which takes a gender, a list of ID's and returns those having that gender (you can safely assume that the CNP has valid form. **Hint:** use functional closures and higher-order functions).
getGender :: Gender -> [ID] -> [ID]
9.1.4. Implement a function which takes a year, a list of ID's and returns those ID's which were born in that year. (Hint, write an auxiliary function which extracts the birth-year of an id. Combine it with higher-order functions).
getYear :: Integer -> [ID] -> [ID]
9.1.5. Define an ADTs called ''Range'', which encodes a **range** of birth years together with a gender. For instance:
- one range could designate people of gender //female// born between 1956 and 2005
- another range could designate both //male// and //female// born between 1991 and 2006
Write a function which takes a ''Range'', a list of ID's and returns those IDs within the range.
getRange :: Range -> [ID] -> [ID]
===== 9.2. Polymorphic datatypes ======
Polymorphic datatypes are those which may be **parametrised**, they may be constructed with respect to other types. A polymorphic datatype is a definition of the form:
data PolyType a b c d ... =
where ''a, b, c, d, ...'' are **type variables**. Type variables can designate any other possible type (although it is possible to add constraints), and they will appear in the **data constructor** definitions.
The simplest polymorphic type definition is the polymorphic list:
data List a = Null | Cons a (List a)
9.2.1. Implement function ''size :: List a -> Integer''.
9.2.2. Implement reverse: ''reverse :: List a -> List a''. (Hint: which auxiliary operations are necessary?).
9.2.3. Implement the conversion functions ''toHaskellList :: List a -> [a]'' and ''fromHaskellList :: [a] -> List a''.