Skip to main content

Make Our Own Types

  • built-in data types, e.g.,Boolean, Int, String, Maybe, etc.
  • make our own data type? One way is to use the data keyword to define a type.

Data declaration

data Maybe a = Nothing | Just a
  • data means that we're defining a new data type.
  • The part before the = is the type, which is Maybe a (vs. Maybe is a type constructor)
  • The parts after the = are value constructors.
    • They specify the different values that this type can have.
    • The | is read as or. (Algebraic Data Type, or ADT)
  • So we can read this as: the Maybe a type can have a value of Nothing or Just a.
  • Both the type name and the value constructors have to be capital cased.
tip

Value constructors are actually functions that ultimately return a value of a data type. And we can map them and partially apply them and everything.

import Data.Number (pi)
import Data.Ord (abs)

data Shape = Circle Number Number Number
| Rectangle Number Number Number Number

surface :: Shape -> Number
surface (Circle _ _ r) = pi * r * r
surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)

Import and run it in repl:

> surface (Circle 10.0 20.0 10.0)
314.1592653589793

> surface $ Rectangle 0.0 0.0 100.0 100.0
10000.0
warning

Type annotation of the surface function: Circle is not a type, Shape is.

  • 🆗 Shape -> Number
  • 🆖 Circle -> Number
info

Pattern match against constructor, like Circle or Rectangle. We just write a constructor and then bind its fields to names.

We can improve our code by defining a new data type Point:

data Point = Point Number Number
data Shape = Circle Point Number
| Rectangle Point Point
note

we used the same name for the data type (Point before =) and the value constructor (Point after =). This has no special meaning, although it's common to use the same name as the type if there's only one value constructor.

Now the surface function can be written as below,

surface :: Shape -> Number
surface (Circle _ r) = pi * r ^ 2
surface (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)
note

In the rectangle pattern, we just used a nested pattern matching to get the fields of the points.