Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding filterM

Tags:

haskell

monads

Consider

filterM (\x -> [True, False]) [1, 2, 3]

I just cannot understand the magic that Haskell does with this filterM use case. The source code for this function is listed below:

filterM          :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
filterM _ []     =  return []
filterM p (x:xs) =  do
    flg <- p x
    ys  <- filterM p xs
    return (if flg then x:ys else ys)

With this use case, p should be the lambda function (\x -> [True, False]), and the first x should be 1. So what does flg <- p x return? What exactly is the value of flg for each recursion?

like image 351
xingmu1978 Avatar asked Mar 05 '15 07:03

xingmu1978


People also ask

How does filter work?

filtration, the process in which solid particles in a liquid or gaseous fluid are removed by the use of a filter medium that permits the fluid to pass through but retains the solid particles. Either the clarified fluid or the solid particles removed from the fluid may be the desired product.

What is filter types of filter?

The four primary types of filters include the low-pass filter, the high-pass filter, the band-pass filter, and the notch filter (or the band-reject or band-stop filter).

How many types of filters are there?

There are seven commonly used home air filter types: HEPA filters. UV light filters. Electrostatic filters.

What is the order of the filter?

The order of a filter is given as an integer value and is derived from the filter's transfer function. As an example, all other factors being equal, a fourth-order filter will roll off twice as fast as a second-order filter, and four times faster than a first-order unit.

What is the difference between filter and filterm?

By comparing the type signatures of filter and filterM we can see that filterM is just filter where the conditional expression yields a Bool within a context m and where the matching results are aggregated in the m context. The implementation of filterM in GCH base is as follows:

What is the function of filter?

A filter is a circuit capable of passing (or amplifying) certain frequencies while attenuating other frequencies. Thus, a filter can extract important frequencies from signals that also contain undesirable or irrelevant frequencies. In the field of electronics, there are many practical applications for filters.

What are the different types of filters in electronics?

Four Major Types of Filters. The four primary types of filters include the low-pass filter, the high-pass filter, the band-pass filter, and the notch filter (or the band-reject or band-stop filter ). Take note, however, that the terms "low" and "high" do not refer to any absolute values of frequency, but rather they are relative values ...

What are the different types of filters used in analog to digital conversion?

Analog-to-digital conversion: Filters are placed in front of an ADC input to minimize aliasing. The four primary types of filters include the low-pass filter, the high-pass filter, the band-pass filter, and the notch filter (or the band-reject or band-stop filter ).


1 Answers

The list monad [] models non-determinism: a list of values [a] represents a number of different possibilities for the value of a.

When you see a statement like flg <- p x in the list monad, flg will take on each value of p x in turn, i.e. True and then False in this case. The rest of the body of filterM is then executed twice, once for each value of flg.

To see how this happens in more detail, you need to understand the desugaring of do notation and the implementation of the (>>=) operator for the list monad.

do notation gets desugared line-by-line into calls to the (>>=) operator. For example the body of the non-empty filterM case turns into

p x >>= \flg -> (filterM p xs >>= \ys -> return (if flg then x:ys else ys))

This is completely mechanical as it's in essence just replacing flg <- before the expression with >>= \flg -> after the expression. In reality pattern-matching makes this a little more complicated, but not much.

Next is the actual implementation of (>>=), which is a member of the Monad type class and has a different implementation for each instance. For [], the type is:

(>>=) :: [a] -> (a -> [b]) -> [b]

and the implementation is something like

[] >>= f = []
(x:xs) >>= f = f x ++ (xs >>= f)

So the loop happens in the body of (>>=). This is all in a library, no compiler magic beyond the desugaring of the do notation.

An equivalent definition for (>>=) is

 xs >>= f = concat (map f xs)

which may also help you see what's happening.

The same thing then happens for the recursive call to filterM: for each value of flg, the recursive call is made and produces a list of results, and the final return statement is executed for each element ys in this list of result.

This "fan-out" on each recursive call leads to 2^3 = 8 elements in the final result of filterM (\x -> [True, False]) [1, 2, 3].

like image 167
GS - Apologise to Monica Avatar answered Sep 20 '22 20:09

GS - Apologise to Monica