• A+
Category：Languages

I'm new to Haskell, I've to do a function that counts the number of vowels in a string using the higher order function foldr

I've tried to create this function

``vowels [] = 0 vowels (x:xs)= if elem x "aeiou" then 1 + vowels xs else vowels xs ``

But it doesn't work and I'm not able to do it using `foldr`, any suggestion?

Well a `foldr :: (a -> b -> b) -> b -> [a] -> b` is a function where the first parameter is a function `f :: a -> b -> b`. You can here see the `a` parameter as the "head" of the list, the second parameter `b` as the result of the recursion with `foldr`, and you thus want to produce a result in terms of these two for the entire function. This logic is basically encapsulated in the second clause of your function.

Indeed:

``vowels (x:xs) = if elem x "aeiou" then 1 + vowels xs else vowels xs ``

can be rewritten as:

``vowels (x:xs) = if elem x "aeiou" then 1 + rec else rec     where rec = vowels xs``

and `rec` is thus the outcome of the recursive call, the second parameter of the "fold"-function. `x` on the other hand is the first parameter of the "fold"-function. We thus need to write this function, only in terms of `x` and `rec`, and this is simply:

``/x rec -> if elem x "aeiou" then 1 + rec else rec``

Furthermore we need to handle the case of an empty list, this is the first clause of your function. In that case the result is `0`, this is the second paramter of the `foldr`, so we got:

``vowels = foldr (/x rec -> if elem x "aeiou" then 1 + rec else rec) 0``

Or a more clean syntax:

``vowels = foldr f 0     where f x rec | elem x "aeiou" = 1 + rec                   | otherwise = rec``

We can further clean it up, by abstracting away `rec`:

``vowels = foldr f 0     where f x | elem x "aeiou" = (1+)               | otherwise = id``