Reputation: 919
The very first 1-Haskell-a-Day exercise confuses me to a point of no return. The objective is to filter out elements of a list unless it's equal to the one following. E.g.
> filterByPair [1, 2, 2, 2, 3, 3, 4]
[2,2,3]
(I was trying to make two offset lists, zip them into tuples and remove the tuples that didn't have the same number both times, e.g. [(2,2),(2,2),(3,3)], etc.)
But the mind-blowingly simple solution uses the =<<
binding operator:
filterByPair :: Eq a => [a] -> [a]
filterByPair = (init =<<) . group
I'm having trouble figuring that operator out. I don't get the same results in ghci when I try to use it:
> init =<< [2,3,4]
No instance for (Num [b0]) arising from the literal `2'
I find that in ghci I can use, say, replicate
with =<<
. It seems to be feeding each element of the list into the function:
> replicate 2 =<< [2,3,4]
[2,2,3,3,4,4]
So the first go-around is equivalent to:
> replicate 2 2
[2,2]
It somehow knows to put the list in the second argument of replicate
, not the first, and to output them all in one big list rather than separate ones, like fmap
does:
> fmap (replicate 2) [2,3,4]
[[2,2],[3,3],[4,4]]
I've read that the binding operator is defined by the monad being used. It's a monad function isn't it? Where's the monad with filterByPair
? Does it have something to do with the Eq
typeclass in its signature?
Likewise, if I use =<<
on its own in ghci, what monad is being used there?
Upvotes: 4
Views: 191
Reputation: 6778
First, filterPairs
rewritten into pointful form for clarity:
filterPairs xs = group xs >>= init
We'll be able to get a good idea what's happening from the types alone.
xs :: Eq a => [a]
group :: Eq a => [a] -> [[a]]
init :: [a] -> [a]
(>>=) :: Monad m => m a -> (a -> m b) -> m b
The first argument to (>>=)
is group xs :: [[s]]
, so if we substitute m ~ []
and a ~ [s]
in (>>=)
we'll get
(>>=) :: [[a]] -> ([a] -> [s]) -> [s]
So we're using the Monad
instance of []
here, which is equivalent to concatMap
(check the types!). Now we can rewrite filterPairs
again
filterPairs xs = concatMap init (group xs)
Now if you figure out how concatMap
, init
and group
work, you should be able to figure how the original filterPairs
works.
Upvotes: 5