0

I am writing a function that can take a string that contains spaces to produce the output such as this: "http://cs.edu/my space/.html" == "http://cs.edu/my%20space/.html" I successfully have it using concat, but I want it with recursion now this is what I came up with until now:

changer [] = []

changer (x:xs) = go x    xs

          where   go ' '  []     = "%20" 
                  go y    []     = [y] 
                  go ' '  (x:xs) = '%':'2':'0': go x xs  
                  go y    (x:xs) = y: go x xs

I can not figured out how to use guard efficiently here, or something else appropriate that working fine. Obviously, I am not using recursion effectively as above code, I need a help to reform it using recursion and with the appropriate type signature for my function changer.

The following is my other code i tried to recursive the main function changer instead of using go the helper:

sanitize [] = []

sanitize (x:xs) 

   |sanitize x    xs     = sanitize xs
   |sanitize y    []     = [y] 
   |sanitize ' '  (x:xs) = '%':'2':'0': go x xs  
   |sanitize y    (x:xs) = y: go x xs
       where   go ' '  []     = "%20" 

It is complaining about y " Not in scope: `y'" Thanks a lot!

7
  • I'm not sure I understand. That code is recursive and your example case looks like it works. Commented Nov 3, 2014 at 5:07
  • Yeah that's true but I want to recursive the function changer instead of using the go helper. Or you think it is still called recursive?? Commented Nov 3, 2014 at 5:10
  • 1
    of course it is still called recursive Commented Nov 3, 2014 at 5:14
  • 1
    Well, it is definitely recursive as it stands. You perform one additional step and then immediately use a recursive function for the rest of the algorithm, so it is definitely recursive in its essence. If you do want an answer to that question though, you should post the code that's giving an error as well as the error. Commented Nov 3, 2014 at 5:21
  • 1
    No problem! You are trying to use the guards like pattern matching. You should pattern match with sanitize in the same way you did with go originally (you didn't need any |s). Commented Nov 3, 2014 at 5:31

3 Answers 3

3

In fact, you’re trying to make it more complicated than it needs to be :

module Main where

changer :: String -> String
changer []       = []
changer (' ':xs) = "%20" ++ changer xs
changer (x:xs)   = x:changer xs

main = do
    print $ changer "http://cs.edu/my space.html"

(You were trying to test many more cases than necessary and, as David Young said, you were using an intermediate function)

It also seems you’re confusing pattern matching and guards. What you need here is pattern matching. Guards are about predicates which evaluate to True or False.

If you really want to write it with guards, it should look like this

sanitize :: String -> String
sanitize xs
   | xs == []       = []
   | head xs == ' ' = "%20" ++ sanitize (tail xs)
   | otherwise      = head xs:sanitize (tail xs)
Sign up to request clarification or add additional context in comments.

Comments

1

While the style that @zigazou has shown is perfectly acceptable and correct, I would prefer avoiding explicit recursion and factor out the conversion function like

urlEncodeChar :: Char -> String
urlEncodeChar ' ' = "%20"
urlEncodeChar '%' = "%25"
urlEncodeChar x   = [x]

changer :: String -> String
changer = concatMap urlEncodeChar

Doing it this way means that you have a much simpler function to edit when you need to add a new mapping, the pattern matching is much more clear, and then you let concatMap handle joining all those values together efficiently.

Comments

0

I really do not know which one the best beside that you both guys correct and appreciated your answers. I have solved it after David Young discussion and help as below:

sanitize :: String -> String

sanitize [] = []

sanitize (x:xs) = sanitize x xs

      where   sanitize ' '  []     = "%20" 
              sanitize y    []     = [y] 
              sanitize ' '  (x:xs) = '%':'2':'0': sanitize x xs  
              sanitize y    (x:xs) = y: sanitize x xs

1 Comment

My code is just a school solution where the function does everything without any help of other functions. Bheklilr version is better since it follows the single responsibility principle by having urlEncodeChar and changer working separately. You can also note that yours and mine do two different recursive calls which can be avoided. Also note you should differentiate your two sanitize functions (global/local).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.