====== 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''.