views:

122

answers:

1

I am trying to start learning haskell, and a question came up. Say, I have a function

countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter a z = case z of []        -> ([], 0);
                            (x:xs)    -> (filter a z , length (filter a z))

It returns a list, all the items of which apply to a certain predicate and a length of that list, which is not relevant.

countFilter (<7) [1,2,4,7,11,8,2] will output ([1,2,4,2], 4).

How to create such an output: ([7,11,8], 4) using the same predicate (<7)?

+4  A: 

If I understand your question correctly, you want to return all the elements that don't match the predicate (< 7) as the first element of the pair.

In that case you can simply use the not function to flip the resulting boolean.
I.e. create a new predicate (\x -> not (oldPred x)), or using function composition: (not . oldPred):

countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter f xs = (filter (not . f) xs, length (filter f xs))

Note that both filter and length can deal with empty lists, so you don't need to write a case yourself.


Alternatively, you can use the partition function to create the two lists, so that you don't filter the list twice:

import Data.List

countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter f xs = let (ys, zs) = partition (not . f) xs
                   in (ys, length zs)

It's probably possible to create an even more efficient version that doesn't use length, but I leave that as an exercise :-)

Tom Lokhorst
excellent! I just didn't notice the "not" in the reference :) Tried to implement "negate" instead ... I didn't yet make it to partitions and importing thought, but I'll get back to your answer, as I'll continue on my Haskell-path.)
Jevgeni Bogatyrjov