4-1-CustomType
4-1-CustomType
Yuepeng Wang
Spring 2025
1
Overview
• Custom data types
• Type synonyms
• Functors
• Kinds
2
Defining New Types
• We can define our own (data) types using the data keyword
• The parts after the equal sign are data constructors (or value constructors)
3
Data Constructors
• Data constructors can take parameters (fields) and produce a value
data Shape = Circle Float Float Float
| Rectangle Float Float Float Float
• Meaning: the Shape type can have circle and rectangle values
• Each circle has three parameters (x, y, radius)
• Each rectangle has four parameters (x, y, length, width)
• Execution
ghci> area (Circle 0 0 1)
3.1415927
ghci> area $ Rectangle 0 0 20 10
200.0
5
Defining Types using Custom Types
• We can use custom types in the definition of a new type
data Point = Point Float Float
data Shape = Circle Point Float
| Rectangle Point Float Float
• Note that we can use the same name for a type and a data constructor
6
Exporting Custom Types
• We can export custom types and data constructors in a module
module Shapes
( Point(..)
, Shape(..)
, originCircle
) where
8
Type Constructors
• Type constructors can take types as parameters and produce a new type
data Maybe a = Nothing
| Just a
9
Type Constructors
• A nullary type constructor (zero parameters) is a type
• Data.Map.Map takes two type parameters: key type and value type
• it takes type parameters and they’re are instantiated (e.g., Maybe Int)
10
Example: Vector
• 3-dimensional vector where all fields have the same type
11
Example: elemIndex
• The elemIndex function in Data.List returns the index of the first element
in the given list which is equal to the query element, or Nothing if there is
no such element
13
Deriving Type Classes
ghci> Vector 'a' 'b' 'c'
<interactive>: ... error:
• No instance for (Show (Vector Char)) ...
• The error is because "Vector a" is not an instance of the Show type class
14
Example: Day
• A Day type that represents the days of a week
data Day = Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday
deriving (Eq, Ord, Show, Read, Enum, Bounded)
• The functions from the Eq, Ord, Show, Read, Enum, and Bounded type
classes are available to use
ghci> read "Monday" :: Day
Monday
ghci> succ Monday
Tuesday
ghci> maxBound :: Day
Sunday
ghci> [Tuesday .. Friday]
[Tuesday,Wednesday,Thursday,Friday]
15
Type Synonyms
• We can create synonyms for types using the type keyword
• Synonyms and original types are interchangeable
• We can partially apply type parameters and get new type constructors
type IntMap v = Map Int v
type IntMap = Map Int
16
Recursive Data Types
• A data constructor can have several fields and each field must be
of some type (can even be the type to be defined)
• We get a recursive data type if the type has itself as a type in the fields
data List a = Empty | Cons a (List a) deriving (Eq, Ord, Show, Read)
• Record syntax
data List a = Empty | Cons { listHead :: a, listTail :: List a }
deriving (Eq, Ord, Show, Read)
17
Recursive Data Types
• A binary tree is an empty tree or a node with a value and two binary trees
data Tree a = EmptyTree
| Node a (Tree a) (Tree a)
deriving (Show)
• A binary search tree (with unique keys) is a binary tree where each node
stores a key greater than all keys in the left subtree but less than all keys
in the right subtree
• Example: write a function to check if a key is in a binary search tree
treeElem :: Ord a => a -> Tree a -> Bool
treeElem k EmptyTree = False
treeElem k (Node x left right)
| k == x = True
| k < x = treeElem k left
| k > x = treeElem k right
18
Type Classes
• A type class defines some function, similar to an interface
• If a type T is an instance of a type class, we can use the functions that the
type class defines with T
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x == y = not (x /= y)
x /= y = not (x == y)
19
Instance of a Type Class
• We can make a custom type an instance of a type class by hand
• Example: traffic light
data TrafficLight = Red | Yellow | Green
20
Instance of a Type Class
• Make TrafficLight an instance of the Show type class
instance Show TrafficLight where
show Red = "Red light"
show Yellow = "Yellow light"
show Green = "Green light"
• Execution
ghci> Green
Green light
21
Subclasses
• We can make type classes that are subclasses of other type classes
• Example
class Eq a => Ord a where
(<=) :: a -> a -> Bool
(<) :: a -> a -> Bool
...
x < y = x <= y && x /= y
• Example: Maybe a
instance Eq a => Eq (Maybe a) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
23
Example: YesNo
• Some weakly typed languages (e.g., JavaScript) treat an “empty” value as
False and other values as True for conditions in if
• Haskell doesn’t work like that, but we can simulate it by a YesNo type
class
class YesNo a where
yesno :: a -> Bool
24
Example: YesNo
• For Bool
instance YesNo Bool where
yesno = id
id :: a -> a is the identity function
• For Maybe a
instance YesNo (Maybe a) where
yesno Nothing = False
yesno _ = True
25
Functors
• The Functor type class is for things that can be mapped over
class Functor f where
fmap :: (a -> b) -> f a -> f b
• A functor in Haskell is an instance of the Functor type class that obeys the
following laws
• fmap id == id
• fmap (g . h) == fmap g . fmap h
26
List as a Functor
• [ ] (List) is a functor
instance Functor [] where
-- fmap :: (a -> b) -> [a] -> [b]
fmap = map
• map id == id
27
Maybe as a Functor
• Maybe is a functor
instance Functor Maybe where
-- fmap :: (a -> b) -> Maybe a -> Maybe b
fmap f (Just x) = Just (f x)
fmap _ Nothing = Nothing
28
Tree as a Functor
• Tree is also a functor
instance Functor Tree where
-- fmap :: (a -> b) -> Tree a -> Tree b
fmap f (Node x left right) = Node (f x) (fmap f left) (fmap f right)
fmap _ EmptyTree = EmptyTree
• Execution example
ghci> fmap (+1) (Node 2
(Node 1 EmptyTree EmptyTree)
(Node 3 EmptyTree EmptyTree))
Node 3 (Node 2 EmptyTree EmptyTree) (Node 4 EmptyTree EmptyTree)
ghci> fmap (+1) EmptyTree
EmptyTree
29
Either a as a Functor
• Either a b has two type parameters, but we can partially apply the type
constructor to obtain “Either a”, which is also a functor!
instance Functor (Either a) where
-- fmap :: (b -> c) -> Either a b -> Either a c
fmap f (Right x) = Right (f x)
fmap _ (Left x) = Left x
• Execution example
ghci> fmap (+1) (Right 10)
Right 11
ghci> fmap (+1) (Left "error")
Left "error"
30
Example: inc
• Define a general increment function on functors
• What is its type?
inc :: (Functor f, Num a) => f a -> f a
inc = fmap (+1)
• Execution example
ghci> inc [1, 2, 3]
[2,3,4]
ghci> inc (Just 10)
Just 11
ghci> inc (Node 1 EmptyTree (Node 2 EmptyTree EmptyTree))
Node 2 EmptyTree (Node 3 EmptyTree EmptyTree)
ghci> inc (Right 10)
Right 11
31
Kinds
• Functions take parameters to produce values. Type constructors take
parameters to produce types (eventually)
• Type is an attribute of data. Kind is an attribute of type (“type” of type)
ghci> :k Int
Int :: *
ghci> :k Maybe
Maybe :: * -> *
ghci> :k Either
Either :: * -> * -> *
32