CITS3211
FUNCTIONAL PROGRAMMING
4. Types
Summary: This lecture discusses the Haskell type system, including parametric polymorphism and adhoc polymorphism using type classes.
CITS3211 Functional Programming 1 4. Types
Types in Functional Programming
● Languages can be divided into one of two classes: dynamically typed and statically typed.
Statically typed languages perform type checking prior to program execution.
Dynamically typed languages do not.
● Modern functional languages (like Haskell, ML and OCaml) are often statically typed, with particularly sophisticated type systems, however LISP and related languages are dynamically typed.
● Static typing can be particularly powerful and useful in a functional language because functions only map from inputs to outputs, and types can describe exactly what kinds of inputs and outputs are allowed.
● Static typing allows a majority errors to be quickly caught and fixed.
● It also allows a lot of the basic structure of the program to be made explicit by the programmer.
CITS3211 Functional Programming 2 4. Types
Types in Functional Programming
● Types in functional languages have a long history: concepts like parametric polymorphism have been studied in typed λcalculus since the 1930s.
● Type systems for other languages have been highly influenced by functional programming (notable recently: the addition of parametric polymorphism to Java and C#).
● Much current research in functional programming concerns even more sophisticated type systems.
● This topic focuses only what is in Haskell, but we will come back to types later in the unit.
CITS3211 Functional Programming 3 4. Types
Type synonyms
• A new name for an old type• Used principally to enhance the readability of a program
type Name = String
type Address = [String]
type Day = Int
type Month = Int
type Year = Int
type Date = (Day, Month, Year)
CITS3211 Functional Programming 4 4. Types
Enumerated datatypes
• A datatype which is defined by listing all possible values of the type− cf. Bool
• A datatype to represent the days of the week might be defined by
data Day = Mon | Tues | Wed | Thurs | Fri | Sat | Sun
• Day is a new type, with seven possible values• Mon, etc. are constructors, which can be used anywhere
that any other values can be used− constructors can be used in expressions and in patterns
• Both typenames and constructornames must start with a capital letter
CITS3211 Functional Programming 5 4. Types
Composite datatypes
• A datatype whose values contain values of other types− cf. tuple types
• A datatype to represent the roots of a quadratic equation might be defined by
type Complex = (Float, Float)
data Roots = Onereal Float| Tworeals Float Float| Onecomplex Complex| Twocomplex Complex Complex
• Complex is a type synonym• Roots is a new type and Onereal, Tworeals, Onecomplex
and Twocomplex are constructor functions− Onereal has type Float -> Roots
− Tworeals has type Float -> Float -> Roots
− Onecomplex has type Complex -> Roots
− Twocomplex has type Complex -> Complex -> Roots
• Constructor functions can be used anywhere that any other functions can be used
mkroots :: [Float] -> [Roots]
mkroots xs = [Onereal x | x <- xs]
CITS3211 Functional Programming 6 4. Types
Recursive datatypes
• A datatype whose values contain values of the same type− cf. lists
• A datatype to represent binary trees of integers might be defined by
data Inttree = Leaf Int | Branch Inttree Int Inttree
• Inttree is a new type and Leaf and Branch are constructor functions− Leaf has type Int -> Inttree
− Branch has type Inttree -> Int -> Inttree -> Inttree
• Functions over composite and recursive datatypes are often defined by cases using patternmatching
CITS3211 Functional Programming 7 4. Types
Haskell typeinference
• When a program is submitted for compilation, the Haskell system− infers the most general type of each function in the
program, and− checks that the type declaration given for each function
is not more general than the inferred type• We will be studying typeinference algorithms later in
CITS3211• A function’s declaration is allowed to “overconstrain” the
function, but it is not allowed to “underconstrain” it, e.g.
f (n, x) = n /= ‘x’
f :: (Char, a) -> Boolis the most general type
f :: (Char, String) -> Boolis OK: overconstrained(but not usually desirable)
f :: (b, a) -> Boolis not OK: underconstrained
• Here, a and b are type variables: they denote any type
CITS3211 Functional Programming 8 4. Types
Polymorphic functions
• Some functions can take arguments of any type, e.g. fst
returns the first element of any 2tuple
fst :: (a, b) -> a
fst (x, y) = x
• Again, a and b are type variables: they denote any type•Type variables must start with a small letter•A function that operates over more than one type is a
polymorphic function• All occurrences of a type variable a (or b, or whatever) in a
given context denote the same type
flip :: (a -> b -> c) -> b -> a -> c
flip f x y = f y x
flip (–) 4 15 is OK
flip (&&) False True is OK
flip elem [1 .. 8] 35 is OK
flip (&&) 4 True is not OK
CITS3211 Functional Programming 9 4. Types
Polymorphic datatypes
• Lists can contain elements of any type− the formal declaration of lists is given by
data [a] = [] | a : [a]
• Userdefined datatypes can also contain elements of any type
data Inttree = Leaf Int | Branch Inttree Int Inttree
data Gentree a = Leaf a | Branch (Gentree a) a (Gentree a)
• Gentree is a typeconstructor− typeconstructors can have any number of arguments− typeconstructors must always be applied to the right
number of arguments
CITS3211 Functional Programming 10 4. Types
Categories of functions
• not is a function which is monomorphic
not :: Bool -> Bool
− not can be applied to values of only one type• length is a function which is parametrically polymorphic
length :: [a] -> Int
− length can be applied to values of an infinite number of types
− length behaves in exactly the same way with all of these types
• * is a function which is adhoc polymorphic or overloaded
(*) :: Int -> Int -> Int
(*) :: Float -> Float -> Float
− * can be applied to values of a finite number n of types, where n > 1
− * behaves differently with different types• * works on types in the type class Num
CITS3211 Functional Programming 11 4. Types
Example
• What is the most general type of sqr?
sqr x = x * x
• We want sqr to work for any type that has * defined, e.g. Int, Integer, Float, Double, etc− but not for Char, Bool, [Int], etc
sqr :: Num a => a -> a
• The class Num is defined by (this is a cutdown version)
class Num a where
(+), (–), (*) :: a -> a -> a
negate :: a -> a
x – y = x + negate y
• Int and Float (and others) are instances (i.e. members) of Num, e.g.
instance Num Int where
(+) = primIntPlus
(*) = primIntMultiply
negate = primIntNegate
CITS3211 Functional Programming 12 4. Types
Type classes
• Haskell has many predefined type classes− many of the predefined functions and operators are
valid only for types in certain type classes• Eq: types that have equality defined
− ==, /=• Ord: types that have an ordering defined
− total orders− <, <=, >, >=, min, max, compare
• Enum: enumerated datatypes− can be used in arithmetic series− toEnum and fromEnum (chr/decode and ord/code)
• Show: types that have a printing function defined− show :: Show a => a -> String
• Read: types that have a parsing function defined− read :: Read a => String -> a
• Bounded: finite types with a smallest and largest value− minBound, maxBound :: Bounded a => a
• Other classes are described in the Haskell report• The predefined classes are defined in a multiple
inheritance hierarchy
CITS3211 Functional Programming 13 4. Types
Derived instances
• When you declare a new datatype, the system can automatically derive functions in the predefined classes
data Gentree a = Leaf a | Branch (Gentree a) a (Gentree a)
deriving (Eq, Show)
− given this declaration, the system will define equality functions (==, /=) and printing functions (show) for Gentree
• You will nearly always want to do this (and remember you may want functions in other classes derived too)− the principal exceptions will be
− when you define an abstract datatype− when you want to override the default definitions
(e.g. for read/show/==/whatever)
CITS3211 Functional Programming 14 4. Types