Jon Fairbairn jon.fairbairn at cl.cam.ac.uk
Wed Aug 9 12:11:53 EDT 2006

```On 2006-08-08 at 15:40BST I wrote:
> I'm curious to know how this performs:
>
> > filterM p = fmap catMaybes . mapM (predMToMaybe p)

> since this definition of filterM clearly shouldn't hold onto
> anything in the second half (. mapM (predMToMaybe p))

... because the above statement is wrong: mapM has the same
problem as the original filterM.

If we replace mapM thus:

> mapM f  = mapM' [] f
> mapM' acc p [] = return (reverse acc)
> mapM' acc p (h:t)
>     = do e <- p h
>          (mapM' \$! (e:acc)) p t

then we get something that doesn't overflow the stack on
Spencer's fuse test, but which doesn't diverge on

> do filterM (\x -> return undefined) [1]; return ()

The new mapM is spine-strict on the list, but so, I think,
is the old version -- at least

> (mapM (return . (+1)) [1..]) >>= print.head

diverges for both versions

The speed of my filterM leaves a lot to be desired: it seems
to be something like one eighth the speed of Spencer's on
the fuse benchmark and one quarter on "none".  Perhaps
someone who understands the ins and outs of these things
better than I do could explain?

[It's not the use of maybes, because

> filterM_strict p = foldr cm (return []) . map (predMToMaybe p)
>     where cm x xs
>               = do c <- x
>                    case c of Just x -> xs >>= return . (x:)
>                              Nothing -> xs

is competetive with Spencer's version (and as strict)]

It does seem to be faster in at least some cases than