Lecture 19-2
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
-
data Point = Point Int Int deriving (Show, Read, Eq) distance :: Point -> Int distance (Point x y) = x + y
-
data HTTPResponse = Data Int String | Error String deriving (Show, Read, Eq)
-
data Student = Student {name :: String address :: String marks :: [Int] } deriving (Show, Read, Eq)