mapMaybe

The basic mapMaybe function resides in the Data.Maybe moduleData.Maybe of the base library, but it is not available in the Prelude module. It is a useful filtering function.

λ> import Data.Maybe

λ> :type mapMaybe
mapMaybe :: (a -> Maybe b) -> [a] -> [b]

It takes an (a -> Maybe b) function and maps that over a list of a values. The return values is a list of b: any Nothing values from the application of the (a -> Maybe b) function will be filtered out, and the Just constructors will also be removed from the final list. The documentation gives a good example, altered a bit here to use type applications:

λ> :set -XTypeApplications

λ> import Text.Read ( readMaybe )

λ> :type readMaybe
readMaybe :: Read a => String -> Maybe a

λ> mapMaybe (readMaybe @Int) ["1", "2", "Julie", "3", ""]
[1,2,3]

@Int is a type application that tells readMaybe what the return type should be; the “read” functions usually need to be told what type of value they are trying to “read” out of the strings they’re applied to. Notice how it nicely filters out the values that cannot be read as Int values.

While the basic mapMaybe is specialized to lists, there are plenty of other versions of it around, specialized to other types of collections.

And there is another we’d like to highlight, a less specialized version in the witherable package.Data.Witherable

mapMaybe :: Filterable f =>
    (a -> Maybe b) -> f a -> f b

In this package, mapMaybe is one of the two primary methods of the typeclass called Filterable, which is described as being like Functor, but with Maybe effects. In turn, Filterable allows us to have a special kind of “traversable” typeclass called Witherable that allows for traversal of data structures while pruning – or “withering” – them by removing some elements (the Nothings). You’ll find instances here for some of the same types we just listed as having specializations of mapMaybe (Vector, Map, etc.) but here they’re gathered into one typeclass.

λ> :m Data.Char Data.Witherable Data.Map

λ> isWord xs = if (all isAlpha xs) then (Just xs) else Nothing
isWord :: Foldable t => t Char -> Maybe (t Char)

λ> Data.Witherable.mapMaybe isWord (fromList [(5,"a"), (3," ")])
fromList [(5,"a")]

λ> Data.Map.mapMaybe isWord (fromList [(5,"a"), (3," ")])
fromList [(5,"a")]

Note that the mapMaybe from Data.Witherable and Data.Map are the same for the Map type.

And a few, such as an instance for Either, are available that don’t exist elsewhere.

λ> fmap isWord (Right "123")
Right Nothing

λ> Data.Witherable.mapMaybe isWord (Right "123")
Left ()

Join Type Classes for courses and projects to get you started and make you an expert in FP with Haskell.