I am trying to write a function that takes in a predicate and a list and returns a list that satisfies the predicate.
So, for instance, I want something like this:
haskell> count_if (x > 3) [2,3,4,5,6]
[4,5,6]
Here’s what I have so far:
count_if f [] = 0
count_if f (x:xs)
| f x = x : count_if f xs
| otherwise = count_if f xs
My question is, how do I test this function using a predicate?
Your
countiffunction is struggling to count anything because you told it to make a list:Notice that
1:[2,3]=[1,2,3], so:is for putting an extra element on the front of a list. If you want to count, you want a number, not a list. (Puttingxon the front sounds a lot likefilter, which gives you all the elements where your predicate is true, but you wanted to count, which is different.)You’ll spot this type of error more easily if you tell the compiler what you were expecting by giving an explicit type signature like
count_if :: (a -> Bool) -> [a] -> Int. Instead of puttingxon the front withx:, let’s add one with1+, givingNow that can be tested like this:
Now you can make
count_ifusingfilter. The type of filter isfilter :: (a -> Bool) -> [a] -> [a]and it gives just the elements that you need:but then do length on the result:
But that can be written slightly neater as
because
.is function composition – this says filter withf, then take the length.(Pointfree geeks would prefer to write this as
countif = (length.).filterbut that’s a lesson for another day!)Using standard functions like
filterandlengthcan result in performance enhancements you might not spot by yourself. If you testcountif (>0) [1..1000000]againstcount_if (>0) [1..1000000], you’ll find it runs noticably faster. It’s a good idea to get to know prelude functions likefilter,foldr,scanretc from the prelude because of this.