# filterM

Here is filter and its monadic cousin filterM:

This is my attempt to understand the relevance of the differences between these two functions. Please leave a comment to let me know about anything I’ve misunderstood. :)

## Filtering with Maybe

We can use the non-monadic filter to get a list of even numbers, or use fmap to apply this filter inside a monad (or any functor):

The filterM form gives us something fmap and filter can’t, and that’s allowing us to interact with a monadic context.

For example, say we want to filter out even numbers from an [Int], but we don’t want to return anything if any number is less than or equal to 0 (perhaps we want to call a function that only works with positive integers).

filter takes a predicate (a -> Bool) which can only evaluate to True or False for each element – there is no way for it to interact with a monadic environment, even if it is mapped into one. Nor can fmap for that matter, as it works with functions (a -> b) and preserves the structure it is mapping over.

filterM doesn’t have this restriction due to its (a -> m Bool) argument, which in this case can produce Just True, Just False, or stop the computation by evaluating to Nothing.

## Parser example

We can apply a similar filter function to a monadic parser.

If we have an instance of a Parser [Int] that parses comma-separated numbers, we can filter even numbers like in our previous example:

Now we want to filter even numbers from our parser, but we want to stop parsing if we get 0 or a negative number. We can use filterM to construct a new parser from our csv parser that does this:

## State example

Another example from Tony Morris’s Haskell exercises is getting a distinct list of elements using the State monad with a Data.Set to keep track of which elements have been seen:

filterM ensures that the state (the contents of the Data.Set) is preserved as each element in the source list is traversed.

## IO example

Say we want to filter a list of files paths to only include files that exist. This requires checking the file system, which requires a FilePath -> IO Bool function called doesFileExist:

## Conclusion

What hadn’t really twigged for me previously is that filterM’s first argument (a -> m Bool) lets us do standard filtering like filter, but gives us the additional option to keep some monadic effect while filtering, such as canceling a computation with Nothing or by failing parsing, or updating some state. In contrast, mapping filter inside a monad does not give us this ability to interact with that effect1.

1. I think this limitation can also be a big advantage. Using fmap means we know we aren’t going to interacting with a monadic context, so we can safely transform an m a without being concerned about ill effects.