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)