J.doe
J.doe

Reputation: 373

Wrong in my guard expression?

I am writing a small program which "builds up" a string from another string (which is the "input string"(parameter)). However I am getting a parse error(on input '='). I suspect I am doing something wrong with my guard expression ?

checkCons :: Char -> Bool 
checkCons x = notElem x ['a','e','i','o','u','y'] 


rovarSprak :: [Char] -> [Char] -> [Char]
rovarSprak [] res = res
rovarSprak (c:restOfStr) res
    | (checkCons c) == True  =  rovarSprak restOfStr (c:'o':c:res)
    | otherwise = rovarSprak restOfStr (c:res)

If I make the call: rovarSprak "abc" [] . I expect "abobcoc".

Observe that the checkCons function is working as desired.

Upvotes: 1

Views: 106

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476584

I think your old code was not properly indented. If I run the ghc compiler on:

rovarSprak :: [Char] -> [Char] -> [Char]
rovarSprak [] res = res
rovarSprak (c:restOfStr) res
| (checkCons c) == True  =  rovarSprak restOfStr (c:'o':c:res)
| otherwise = rovarSprak restOfStr (c:res)

it gives an error:

strep.hs:8:1: parse error on input ‘|’

rewriting this to:

rovarSprak :: [Char] -> [Char] -> [Char]
rovarSprak [] res = res
rovarSprak (c:restOfStr) res
    | (checkCons c) == True  =  rovarSprak restOfStr (c:'o':c:res)
    | otherwise = rovarSprak restOfStr (c:res)

solves the compile error.

Furthermore If try to reproduce it, the result is:

"cocboba"

The guards are working fine, the only problem with your code is that in the recursive call:

rovarSprak restOfStr (c:'o':c:res)
--                   ^push in front

you push the result in front of the new list whereas you probably want it to be at the tail.

You can solve this by not working with an accumulator, but emitting elements straight away. For example:

rovarSprak :: [Char] -> [Char]
rovarSprak [] = []
rovarSprak (c:restOfStr)
    | (checkCons c) == True =  c : 'o' : c : (rovarSprak restOfStr)
    | otherwise = c : rovarSprak restOfStr

(emission in boldface and stroke redundant code elements). This also allows lazy list generation: perhaps you are only interested in the first three elements of the output, or perhaps the input is an infinite list.

A final optimization I propose is to swap the two lines of rovarSprak:

rovarSprak :: [Char] -> [Char]
rovarSprak (c:restOfStr)
    | checkCons c =  c : 'o' : c : (rovarSprak restOfStr)
    | otherwise = c : rovarSprak restOfStr
rovarSprak [] = []

this is because it is more likely you will have a match on the first line: for a list with length N there will be N calls on the first pattern and one on the second pattern.

Upvotes: 1

Related Questions