Haskell Language Type Classes Maybe and the Functor Class


In Haskell, data types can have arguments just like functions. Take the Maybe type for example.

Maybe is a very useful type which allows us to represent the idea of failure, or the possiblity thereof. In other words, if there is a possibility that a computation will fail, we use the Maybe type there. Maybe acts kind of like a wrapper for other types, giving them additional functionality.

Its actual declaration is fairly simple.

Maybe a = Just a | Nothing

What this tells is that a Maybe comes in two forms, a Just, which represents success, and a Nothing, which represents failure. Just takes one argument which determines the type of the Maybe, and Nothing takes none. For example, the value Just "foo" will have type Maybe String, which is a string type wrapped with the additional Maybe functionality. The value Nothing has type Maybe a where a can be any type.

This idea of wrapping types to give them additional functionality is a very useful one, and is applicable to more than just Maybe. Other examples include the Either, IO and list types, each providing different functionality. However, there are some actions and abilities which are common to all of these wrapper types. The most notable of these is the ability to modify the encapsulated value.

It is common to think of these kinds of types as boxes which can have values placed in them. Different boxes hold different values and do different things, but none are useful without being able to access the contents within.

To encapsulate this idea, Haskell comes with a standard typeclass, named Functor. It is defined as follows.

class Functor f where
  fmap :: (a -> b) -> f a -> f b

As can be seen, the class has a single function, fmap, of two arguments. The first argument is a function from one type, a, to another, b. The second argument is a functor (wrapper type) containing a value of type a. It returns a functor (wrapper type) containing a value of type b.

In simple terms, fmap takes a function and applies to the value inside of a functor. It is the only function necessary for a type to be a member of the Functor class, but it is extremely useful. Functions operating on functors that have more specific applications can be found in the Applicative and Monad typeclasses.