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.
mapMaybe :: (a -> Maybe b) -> Vector a -> Vector b
Data.Vector
mapMaybe :: (a -> Maybe b) -> Map k a -> Map k b
Data.Map.Lazy
mapMaybe :: (a -> Maybe b) -> HashMap k a -> HashMap k b
Data.HashMap.Lazy
mapMaybe :: (a -> Maybe b) -> IntMap a -> IntMap b
Data.IntMap.Lazy
And there is another we’d like to highlight, a less specialized version in the witherable
package.Data.Witherable
mapMaybe :: Filterable f =>
-> Maybe b) -> f a -> f b (a
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 Nothing
s). 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 ()