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:

  1. Rectangle
  2. 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:

  1. Rectangle Integer Integer creates the data constructor Rectangle :: Integer → Integer → Shape
  2. 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.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:

  1. zero is a special natural number
  2. 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:
    1. S is the gender and birth-period digit:
      1. S=1 - male born before year 2000
      2. S=2 - female born before year 2000
      3. S=5 - male born starting from 2000
      4. S=6 - female born starting from 2000
    2. DDMMYY indicates the birth date (D-day, M-month, Y-year)
    3. XXXXXX - the last six digits encode other info which are not relevant for us.

or

  • a collection of strings which represent:
    1. Full name
    2. Complete year of birth
    3. 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:

  1. one range could designate people of gender female born between 1956 and 2005
  2. 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]

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.