Maybe Just Nothing

Sunday, 24th May, 2009

Real World Haskell
Chapter 3: Defining types, streamlining functions
Section: Parametrised types

On the first few readings, this section (a single page in the dead tree version) flummoxed me completely. Some of the comments on the book’s web site were helpful, and now I’ve worked through it. This post can bear witness to my journey.


  1. Types
  2. Algebraic data types
  3. Parametrised types
  4. Very Important Note
  5. A Use case
  6. Maybe, Just and Nothing
  7. Note also


Haskell is a strongly typed language. We can make up our own types and we define them like this:

data MyNewType = MyNewTypeGeneratorFunction Args


  • MyNewType is called a type constructor. Must start with a capital letter.
  • MyNewTypeGeneratorFunction is called a value constructor or a data constructor. It’s an ordinary function which takes Args and returns an item of type MyNewType. Must start with a capital letter.
  • Args is a space separated list of components for the type.
  • deriving(Show) is optional. I don’t know what it is yet, but it tells the interpreter how to display the type.

This is the example given in RWH (beginning of Ch 3):

-- file: ch03/BookStore.hs
data BookInfo = Book Int String [String]
Algebraic data types

An algebraic data type can have more than one value constructor:

data MyPty = MyPtyGen Args
           | MyOtherPtyGen OtherArgs

Args and otherArgs can be different.

The example given by RWH (section Algebraic data types, p. 45) is:

-- file: ch03/BookStore.hs
type CardNumber = String
type CardHolder = String
type Address = [String]
type CustomerID = Int

data BillingInfo = CreditCard CardNumber CardHolder Address
                 | CashOnDelivery
                 | Invoice CustomerID
                   deriving (Show)

Where CreditCard, CashOnDelivery and Invoice are generator functions, or value constructors.

Parametrised types

As with templates in C++, we can use type variables or parameters in data definitions:

data MyNewType a = MyNewTypeGeneratorFunction a

The lower case a is the type variable. C. E. Pramode, in a comment on the RWH webiste, and on his own RWH wiki, gives a very clear example of a parametric type:

data Complex a  = Complex {
   real :: a,
   imaginary :: a

Now, we can do at the ghci prompt:

let p = Complex 10 20
let q = Complex 1.2 2.3

So we have p, a Complex number whose real/imag parts are integers and q, another Complex number whose real/imag parts are Doubles.

:type p
Complex Integer


:type q
Complex Double
Very Important Note

You have to have a value constructor, in other words a function which returns an item of the required type. You can’t just return the type variable itself:

data MyBogusType a = a

loading this into ghci will generate the error, Not a data constructor `a'.

[thanks to Darrin Thompson for his comment]

Note that

data MyBogusType a = A

is fine because A is interpreted as a value constructor.

A Use case

Given the above, it might be useful to define a type that is a simple container, but that can also help us with error handling:

-- these first definitions don't work
-- see Dan's comment
-- why did I think they worked?!

-- type WarningType = Int String
-- type ErrorType = Int String

type WarningType = Int
type ErrorType = Int

data Container a = OllKorrekt a
                 | Warning a WarningType
		 | Error ErrorType

In ghci:

  *Main> let x = OllKorrekt "qwerty"
  *Main> x
  OllKorrekt "qwerty"
  *Main> :type x
  x :: Container [Char]
  *Main> let y = Warning "asdasd" 13
  *Main> y
  Warning "asdasd" 13
  *Main> :type y
  y :: Container [Char]
  *Main> let z = Error (-1)
  *Main> z
  Error (-1)
  *Main> :type z
  z :: Container a
Maybe, Just and Nothing

The Maybe data type, with its two value constructors, answers a similar use case. Maybe, Just and Nothing are defined in ghci’s standard library, the Prelude:

data Maybe a = Nothing
             | Just a

The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing). Using Maybe is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error.

The Maybe type is also a monad. It is a simple kind of error monad, where all errors are represented by Nothing. A richer error monad can be built using the Data.Either.Either type.

error and monad we’ll meet again later.

So, Maybe is an ordinary type constructor, and Just and Nothing are ordinary value constructors, and it is the use case of encapsulating optional or exceptional values which is important.

Note also
  • The Prelude defines a maybe function:

    maybe :: b -> (a -> b) -> Maybe a -> b
    The maybe function takes a default value, a function, and a Maybe value. If the Maybe value is Nothing, the function returns the default value. Otherwise, it applies the function to the value inside the Just and returns the result.

  • The module Data.Maybe defines various maybe-related functions (see also RWH section The case Expression, p. 66).

2 Responses to “Maybe Just Nothing”

  1. Dan Says:

    The example in the “A Use case” section needs a tweak. Maybe something like this:

    type WarningType = Int
    type ErrorType = Int

    data Container a = OllKorrekt a
    | Warning a WarningType
    | Error ErrorType

    I couldn’t get it working as is.

  2. llaisdy Says:

    Dear Dan

    Thanks for your comment.

    You’re right! Sorry that got in there. I’ve changed the text.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: