0

How do I replace a character with multiple characters in a string. I can replace a character with another character with below:

  replaceO [] = []
  replaceO (x:xs) =
     if x == '('
     then '\n' : replaceO xs
     else x : replaceO xs

But I want to replace '(' with "\n\t\t", not just '\n'.

---------- UPDATE -------------- Based on the answer below, can I make that a function that accepts a string and returns a string like this:

ReplaceFun str :: String -> String
ReplaceFun str = do
    concatMap (\str -> if str == '.' then "foo" else [str])

This doesn't work, can someone point out my mistake? I am very new to Haskell.

Here is what I have for nested indentation:

replaceO (x:xs) n l =
    if x == '('
    then "\n" ++ (showTabs n "-") ++ replaceO xs (n + 1) 'l'
    else
        if x == ')'
        then "\n" ++ (showTabs n "-") ++ replaceO xs (n - 1) 'l'
        else x : replaceO xs n 'l'
1
  • 1
    You haven't given concatMap enough arguments - the rhs of replaceFun (also note the lowercase) should have type String but concatMap (\str -> if str == '.' then "foo" else [str]) has type String -> String. You probably want replaceFun = concatMap (\str -> if str == '.' then "foo" else [str]) Commented Mar 20, 2016 at 23:40

2 Answers 2

5

Just use concatMap

Prelude> concatMap (\x -> if x == '.' then "foo" else [x]) "example..."
"examplefoofoofoo"
Sign up to request clarification or add additional context in comments.

4 Comments

Can you define this as a function please? I can't get it working.
I did it like this, but doesn't work: replaceFun w :: String -> String replaceFun w = do concatMap (\x -> if x == '.' then "foo" else [x])
can you have a look at the updated part of the question?
@2D3D4D f = concatMap (\x -> if x == '.' then "foo" else [x]) or more generally f a b s = concatMap (\x -> if x == a then b else [x]) s
2

expanding your example, you can substitute "\n\t\t" for "(" by just prepending multiple things to the result of the recursive call

replace1 [] = []
replace1 (x:xs) =
   if x == '('
   then '\n' : '\t' : '\t' : replace1 xs
   else x : replace1 xs

of course, this is equivalent to using "\n\t\t" ++

replace2 [] = []
replace2 (x:xs) =
   if x == '('
   then "\n\t\t" ++ replace2 xs
   else x : replace2 xs

if we note that x : is equivalent to [x] ++

replace3 [] = []
replace3 (x:xs) =
   if x == '('
   then "\n\t\t" ++ replace3 xs
   else [x] ++ replace3 xs

then we can factor out the repeated recursive call

replace4 [] = []
replace4 (x:xs) = (if x == '(' then "\n\t\t" else [x]) ++ replace4 xs

then for clarity, we could filter out the if statement into a function:

replace5 [] = []
replace5 (x:xs) = f x ++ replace5 xs
  where f x = if x == '(' 
              then "\n\t\t" 
              else [x]

we could then reorganize our code - rather than alternately applying f to each x and appending it to our results, we could apply f to all the xs and then concatenate all the results:

replace6 xs = concat $ map f xs
  where f x = if x == '(' 
              then "\n\t\t" 
              else [x]

But concat $ map f xs is used so often that it has another name:

replace7 xs = concatMap f xs
  where f x = if x == '(' 
              then "\n\t\t" 
              else [x]

Actually, it has another one too, because [] is a monad:

replace8 xs = xs >>= f
  where f x = if x == '(' 
              then "\n\t\t" 
              else [x]

But if we're doing that, we might as well go full Monad:

replace9 xs = do
  x <- xs
  if x == '(' 
     then "\n\t\t" 
     else [x]

But I'd probably just stop at replace7, personally.

14 Comments

Thanks @rampion, just realized something, I wanted to use this to pretty print a tree. But all nodes will end up in the same indentation. I wanted to increase the indenting for each nested node. Is that easily possible?
Sure! look at one of the early versions. What if replace2 took another argument, n, for how many tabs to insert after it replaced a '(' with a newline? Now the recursive call takes two arguments - the rest of the string and the number of tabs. What would you give the recursive call if (a) x wasn't a parenthesis, (b) it was an open paren, or (c) it was a close paren?
If it was not a parenthesis, then no replacement needed. If an open parenthesis, then we replace \n and \t (for each level of nested). Close parenthesis can be replaced by empty string I think.
Show me how far you got following my questions above! Did you define a new replace function that took two arguments, xs and n?
2D3D4D: good start! now consider what you want "a(a(a(a(" to look like, and walk through your implementation using that as the input. See if you get what you want. See what goes wrong.
|

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.