Skip to content
UoL CS Notes

Lecture 19-2

COMP105 Lectures

More Complex Custom Types

More Complex Constructors

More complex constructors can contain other types.

data Point = Point Int Int deriving (Show, Read, Eq)

This is saying that the type Point has one constructor called Point and in that constructor there are two Int. The constructor name has no relation to the type name.

It is common that if your type has only one constructor to call constructor the same name as the type.

> Point 1 4
> Point 1 4

> read "Point 10 10" : Point
> Point 10 10

> Point 2 2 /= Point 3 1
> True

It is also common to use pattern matching to work with complex constructors:

shift_up (Point x y) = Point x (y +1)
> shift_up (Point 1 1)
> Point 1 2

> :t shift_up
> shift_up :: Point -> Point

Example

This example completes a computation using almost entirely our own custom types. We are also using pattern matching on our types:

move :: Point -> Direction -> Point

move (Point x y) North = Point x (y+1)
move (Point x y) South = Point x (y-1)
move (Point x y) East = Point (x+1) y
move (Point x y) West = Point (x-1) y
> move (Point 0 0) North
> Point 0 1

More Complex Constructors Continued

Types can have multiple constructors each of which can have their own types:

data Shape = circle Float | Rect Float Float deriving (Show)
> :t Circle 2.0
> Circle 2.0 :: Shape

> :t Rect 3.0 4.0
> Rect 3.0 4.0 :: Shape

Example

area :: Shape -> Float

area (Circle radius) = pi * radius ** 2
area (Rect x y) = x * y
> area (Circle 2.0)
> 12.56371

> area (Rect 3.0 4.0)
> 12.0

Records

You can use data types to build custom records:

data Person = Person String String Int String

get_first_name	(Person x _ _ _) = x
get_second_name	(Person _ x _ _) = x
get_age		(Person _ _ x _) = x
get_nationality	(Person _ _ _ x) = x
> get_age (Person "joe" "bloggs" 25 "UK")
> 25

Record Syntax

To make things easier, Haskell provides a record syntax:

data Person = Person {	firstName :: String,
			secondName :: String,
			age :: Int,
			Nationality :: String}
			deriving (Show)
> Person "joe" "bloggs" 25 "UK"
> Person {firstName = "joe", secondName = "bloggs", age = 25, nationality = "UK"}

This is similar to the previous example where we made our own record type.

Records can be created out of order, whereas normal data types cannot.

data Example = Example {a :: String,
						b :: Int}
						deriving (Show)
> Example "one" 2
> Example {a = "one", b = 2}

> Example {b = 3, a = "zero"}
> Example {a = "zero", b = 3}

If you create an out of order function then you should put them in {} with their labels so that Haskell can identify them.

Example

This example takes a co-ordinate Point to locate the shape in 2D space.

data AdvShape = AdvCircle Point Float | AdvRect Point Point deriving (Show)

area' (AdvCircle _ radius) = pi * radius ** 2
area' (AdvRect (Point x1 y1) (Point x2 y2)) =
	let
		w = abs (x1 - x2)
		h = abs (y1 - y2)
	in
		fromIntergral (w * h)

Exercises

  1.  data Point = Point Int Int deriving (Show, Read, Eq)
     distance :: Point -> Int
     distance (Point x y) = x + y
    
  2.  data HTTPResponse 	= Data Int String 
                 | Error String
                 deriving (Show, Read, Eq)
    
  3.  data Student = Student {name :: String
                 address :: String
                 marks :: [Int]
                 }
                 deriving (Show, Read, Eq)