views:

394

answers:

2

I'm trying to find a way to do the following function with foldl:

count a = length (filter (\i -> i) a)

It just counts the number of values that are true in a list of booleans. I did try it myself with

count = foldl (\i -> 
      case i of
       True -> (1+)
       False -> (0+)
      ) 0

Which did not even compile. Any suggestions?

+9  A: 

So let's check out the types of the functions involved

Prelude> :t (\i -> case i of { True -> (1+) ; False -> (0+) })
(\i -> case i of { True -> (1+) ; False -> (0+) }) :: (Num t) => Bool -> t -> t
Prelude> :t foldl
foldl :: (a -> b -> a) -> a -> [b] -> a

So for your list of Bools, b is Bool, but the function you're using has Bool as the first argument, not the second. The accumulated value is the first argument. So instead you could do

foldl (\acc p -> case p of { True -> acc + 1 ; False -> acc }) 0

Or if you'd just like to fix the argument order, use your original function with flip

Prelude> :t flip
flip :: (a -> b -> c) -> b -> a -> c

foldl (flip (\i -> case i of
                           True -> (1+)
                           False -> (0+)
             )) 0

Or you can be more succinct: foldl (flip ((+) . fromEnum)) 0

Logan Capaldo
the fromEnum is worth knowing about, but depends on a somewhat arbitrary encoded of Bool. It would'nt work (in the bad way - it'd compile and run, but we incorrect) if Bool had been wriiten data Bool = True | False deriving Enum it would be wrong.
ja
data Bool = False | True was done in that order for a reason ;) It's not arbitrary. It's also defined in the report http://www.haskell.org/onlinereport/basic.html , so if you do it another way, it's not Haskell anymore.
Logan Capaldo
Even more succinctly: `sum . (map fromEnum)` – (two passes through the list though, unless you're doing fusion)
Peter Burns
+2  A: 

How about:

count = foldl (\i v -> if v then i + 1 else i) 0

Another way to do it without foldl:

count list = sum $ map fromEnum list

Credit to Logan for pointing out fromEnum. Hadn't heard of that one before.

Jay Conrod
Neat. I'm learning Haskell (started a week ago) and the best I could come up with was:count list = foldl (+) 0 (map (\i -> if i then 1 else 0) list)
eljenso