简体   繁体   中英

change the function to use recursion in Haskell

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!

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)

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM