Fiedberg Nichenko
Fiedberg Nichenko

Reputation: 153

Iterate and count [String] Haskell

I am trying to learn Haskell. Currently I am making a function that should take a [String] and 'char' and return in how many strings this char presents.

count [] _ = 0
count (x:xs) v
 | elem v x = 1 + count xs
 | otherwise = 0 + count xs

How is it done correctly?

!EDIT

I get this error ::

Occurs check: cannot construct the infinite type: a ~ a1 -> a
  Relevant bindings include
  v :: a1 (bound at prog.hs:7:14)
  xs :: [t a1] (bound at prog.hs:7:10)
  x :: t a1 (bound at prog.hs:7:8)
  count :: [t a1] -> a1 -> a (bound at prog.hs:6:1)
In the second argument of `(+)', namely `count xs'
In the expression: 1 + count xs

Upvotes: 0

Views: 2582

Answers (4)

Netwave
Netwave

Reputation: 42678

Just for show a folding solution:

count :: String -> Char -> Int
count x c = foldr (\x y -> y+1 if x == c else y) s 0

foldr pick each element and perform the desired operation taking the result as the input for the next item, so in this case, we are initializing it to 0, and adding 1 for each element that is equal to the char passed to te function.

Upvotes: 1

Xophmeister
Xophmeister

Reputation: 9211

You've got the right idea. elem is a predicate that answers whether a list contains an element. Given that a String is a list of char, it would probably be better to just match on equality. Something like this:

count :: String -> Char -> Int
count "" _ = 0
count (x:xs) v
  | x == v    = 1 + count xs v
  | otherwise = count xs v

Your count function takes two arguments. In your example code, you're missing the second (the character you're searching for); hence the error.


EDIT The signature is count :: [String] -> Char -> Int; my mistake. In which case, you should use elem and it can be simplified to something like:

count :: [String] -> Char -> Int
count [] _ = 0
count (x:xs) v = c + count xs v
                 where c = if elem v x then 1 else 0

...you always do the count xs v recursive call, so you don't really need the guard.

Upvotes: 1

Kapol
Kapol

Reputation: 6463

count takes two arguments (a list and a character), but you are invoking it with only one (xs) in each guard. You should change your function to:

count [] _ = 0
count (x:xs) v
 | elem v x  = 1 + count xs v
 | otherwise = count xs v

Notice that I removed adding zero, because it's redundant and doesn't really make the code more readable.

Upvotes: 1

Glubus
Glubus

Reputation: 2855

I would recommend defining the desired signature for count, so you'll get better errors, and a good feeling for the type system (since you're learning haskell)

count :: [String] -> Char -> Int

To make your code work these are in my mind the changes you'd need to make (untested)

count [] _ = 0
count (x:xs) v
 | elem v x = 1 + count xs v
 | otherwise = count xs v

You could also use built in functions like haskell to make your code a little more readable (less guards and lines), though I think it would make it a little worse performance wise.

Upvotes: 0

Related Questions