Product type

Product type #

A product type can be viewed as a simplistic class, and its values as simplistic objects.

in Haskell #

Declaration #

Syntax. A product type can be declared as

data <product type name> = <constructor> <type 1> ... <type n>

where the product type name and the constructor start with a capital letter.

Example. The following declaration defines a product type Card:

-- a playing card, represented as as suit and a rank
data Card = CardC Suit Int

The constructor for this type is CardC.

Usage #

The constructor lets us create expressions with this type (similarly to a constructor in Java).

Example. The expression

CardC Spades 8

has type Card.

Naming conventions #

Syntax. The name of a constructor is arbitrary.

Example. the type Card can equivalently be declared

data Card = MyConstructor Suit Int

Warning. The name of a product type and its constructor can be identical (as in Java). This is a widely adopted practice in Haskell.

Example.

data Card = Card Suit Int

Convention. In this course, for didactic reasons, we will use different names for a product type and its constructor.

Pattern matching #

A constructor can be used to create a complex pattern.

Example.

data Card = CardC Suit Int

getRank :: Card -> Int
getRank (CardC _ r) = r

isSpades :: Card -> Bool
isSpades (CardC Spades _) = True
isSpades _ = False

Consider the following program:

data Card = CardC Suit Int

aFunction :: [Card] -> [Int]
aFunction [] = []
aFunction (CardC Diamonds r : cs) = r : aFunction cs
aFunction (_ : cs) = aFunction cs
  1. What does the following expression evaluate to?
aFunction
  [
    CardC Diamonds 6,
    CardC Hearts 4,
    CardC Spades 6,
    CardC Diamonds 10
  ]
  1. More generally, what does the function aFunction do?
[6,10]
  1. It maps a list of cards to the ranks of diamond cards that it contains.

Same two questions as above, for the function anotherFunction below (recall the higher-order functions filter and map seen earlier).

data Card = CardC Suit Int

anotherFunction :: [Card] -> [Int]
anotherFunction = map (\(CardC _ r) -> r) . filter (\(CardC s _) -> s == Diamonds)

It is equivalent to the function of the previous exercise.

Record-like notation #

Syntax. Haskell provides an alternative notation for a product type, using attribute names.
For instance:

data Card = CardC { suit :: Suit, rank :: Int }

This is very similar to structures in C or records in Java.

Usage #

An attribute name can be used as regular function to access its value.

Example.

data Card = CardC { suit :: Suit, rank :: Int }

isRed :: Card -> Bool
isRed c = suit c == Diamonds || suit c == Hearts

We can create an expression with this type as follows:

Example. The expression

CardC { suit = Spades, rank = 8 }

has type Card.