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.