Search code examples
haskellanonymous-functionhigher-order-functionsfolding

Folding with anonymous functions


I'm currently trying to learn folding.

But instead of using predefined functions I want to use my own.

So I want to double all vowels in a String.

doubleVowels :: String -> String

My attempt is (yet just for 'a', as I'm try solve it for one letter first and will expand and optimize it, once it runs):

doubleVowels :: String -> String
doubleVowels  a = foldl (\eachChar -> if eachChar == 'a' then (a ++ "aa") else a) "" a

Trying to run he code I'm getting the following erorr:

Experimenting.hs:8:78: error:
    * Couldn't match type `[Char]' with `Char -> Char'
      Expected type: Char -> Char
        Actual type: String
    * In the expression: a
      In the expression: if eachChar == 'a' then (a ++ "aa") else a
      In the first argument of `foldl', namely
        `(\ eachChar -> if eachChar == 'a' then (a ++ "aa") else a)'
  |
8 | doubleVowels a = foldl (\eachChar -> if eachChar == 'a' then (a ++ "aa") else a) "" a
  |                                                                              ^

Experimenting.hs:8:81: error:
    * Couldn't match expected type `Char' with actual type `[Char]'
    * In the second argument of `foldl', namely `""'
      In the expression:
        foldl
          (\ eachChar -> if eachChar == 'a' then (a ++ "aa") else a) "" a
      In an equation for `doubleVowels':
          doubleVowels
            = foldl
                (\ eachChar -> if eachChar == 'a' then (a ++ "aa") else a) "" a
  |
8 | doubleVowels a = foldl (\eachChar -> if eachChar == 'a' then (a ++ "aa") else a) "" a
  |                                                                                 ^^
Failed, no modules loaded.


Solution

  • doubleVowels :: String -> String
    doubleVowels  a = foldr (\eachChar b -> if eachChar == 'a' then ("aa" ++ b) else (eachChar:b)) "" a
    

    In most cases, if there is no specific reason for foldl, use foldr instead of foldl as it allows the Haskell compiler to lazily evaluate your expression. If I remember correctly, even then use foldl', since foldl is not strict and takes too much memory while not giving you any benefit for the laziness.

    Apart from that, you are missing the second argument to foldrs (or foldls) function. foldr has type:

    foldr :: (a -> b -> b) -> b -> t a -> b
    

    The function to foldr has type a -> b -> b where the first argument is the current element of the folding structure and the second is the accumulator. The lambda that you are using has only one parameter.

    In addition, the body of the lambda function also doesn't make much sense.

    if eachChar == 'a' then (a ++ "aa") else a)
    

    a is the parameter that the surrounding function doubleVowels receives. You need to use the parameters of the lambda function here.