The Maybe data type is a means of being explicit that you are not sure that a function will be successful when it is executed.
Many languages require you to guess what they will do when a calculation did not finish properly. For example, an array lookup signature may look like this in pseudocode:
getPosition(Array a, Value v) returns Integer
But what happens if it doesn't find the item? It could return a
null value, or the integer '-1' which would also be an obvious sign that something went wrong. But there's no way of knowing what will happen without examining the code for this procedure to see what the programmer chose to do. In a library without available code this might not even be possible.
The alternative is to explicitly state what the function should return (in this case, Integer), but also that it might not work as intended — Maybe Integer. This is the intention of the Maybe datatype. So in Haskell, we could write the above signature as:
getPosition :: Array -> Value -> Maybe Integer
If the function is successful you want to return the result; otherwise, you want to return an explicit failure. This could be simulated as a tuple of type
(Bool, a) where a is the "actual" return type of the function. But what would you put in the a slot if it failed? There's no obvious answer. Besides which, the Maybe type is easier to use and has a selection of library functions for dealing with values which may fail to return an explicit answer.
The Standard Prelude defines the Maybe type as follows, and more utility functions exist in the Data.Maybe library.
data Maybe a = Nothing | Just a
The type a is polymorphic and can contain complex types or even other monads (such as IO () types).
Data.Maybe, in the standard hierarchical libraries, contains a wealth of functions for working with Maybe values.
There are two obvious functions to give you information about a Maybe value.
This returns True if the argument is in the form
isJust :: Maybe a -> Bool isJust (Just _) = True isJust Nothing = False
The dual of
isJust: returns True if its argument is
isNothing :: Maybe a -> Bool isNothing (Just _) = False isNothing Nothing = True
There are a handful of functions for converting Maybe values to non-Maybe values.
maybe is a function that takes a default value to use if its argument is
Nothing, a function to apply if its argument is in the form
Just _, and a Maybe value.
maybe :: b -> (a -> b) -> Maybe a -> b maybe _ f (Just x) = f x maybe z _ Nothing = z
A frequent pattern is to use the
maybe function, but not want to change the value if it was a
Just. That is, call
maybe with the second parameter being
id. This is precisely
fromMaybe :: a -> Maybe a -> a fromMaybe z = maybe z id
There are certain occasions when you know a function that ends in a Maybe value will produce a
Just. In these cases, you can use the
fromJust function, which just strips off a
fromJust :: Maybe a -> a fromJust (Just x) = x fromJust Nothing = error "fromJust: Nothing"
Lists and Maybe
Lists are, in some ways, similar to the Maybe datatype (indeed, this relationship will be further explored when you learn about monads). As such, there are a couple of functions for converting between one and the other.
This function, and the following one, makes a lot of sense when you think about Maybe and list values in terms of computations (which will be more fully explained in the section on Advanced monads).
 represents a failed computation. With Maybe,
listToMaybe converts between the list and Maybe monad. When the parameter (in the list monad) indicated a successful computation, only the first solution is taken to place in the Maybe value.
listToMaybe :: [a] -> Maybe a listToMaybe  = Nothing listToMaybe (x:_) = Just x
The obvious opposite of
maybeToList :: Maybe a -> [a] maybeToList Nothing =  maybeToList (Just x) = [x]
Finally, there are a couple of functions which are analogues of the normal Prelude list manipulation functions, but specialised to Maybe values.
Continue on some failures (like 'or')
Given a list of Maybe values,
catMaybes extracts all the values in the form
Just _, and strips off the
Just constructors. This is easily defined with a list comprehension, as we showed in the pattern matching chapter:
catMaybes :: [Maybe a] -> [a] catMaybes ms = [ x | Just x <- ms ]
mapMaybe applies a function to a list, and collects the successes. It can be understood as a composition of functions you already know:
mapMaybe :: (a -> Maybe b) -> [a] -> [b] mapMaybe f xs = catMaybes (map f xs)
But the actual definition may be more efficient and traverse the list once:
mapMaybe :: (a -> Maybe b) -> [a] -> [b] mapMaybe _  =  mapMaybe f (x:xs) = case f x of Just y -> y : mapMaybe f xs Nothing -> mapMaybe f xs
Stop on failure
Sometimes you want to collect the values if and only if all succeeded:
sequence :: [Maybe a] -> Maybe [a] sequence  = Just  sequence (Nothing:xs) = Nothing sequence (Just x:xs) = case sequence xs of Just xs' -> Just (x:xs') _ -> Nothing