## 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.

**Contents:**

- Types
- Algebraic data types
- Parametrised types
- Very Important Note
- A Use case
- Maybe, Just and Nothing
- Note also

**Types**

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

data MyNewType = MyNewTypeGeneratorFunction Args

deriving(Show)

Where:

`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] deriving(Show)

**Algebraic data types**

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

data MyPty = MyPtyGen Args | MyOtherPtyGen OtherArgs deriving(Show)

`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 deriving(Show)

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 }deriving(Eq,Show)Now, we can do at the ghci prompt:

let p = Complex 10 20 let q = Complex 1.2 2.3So 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 IntegerAnd:

: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 deriving(Show)

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 *Main>

**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 aThe

`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).

Thursday, 2nd February, 2012 at 1:53 pm

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

deriving(Show)

I couldn’t get it working as is.

Wednesday, 8th February, 2012 at 9:43 pm

Dear Dan

Thanks for your comment.

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

Ivan