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'
Just use concatMap
Prelude> concatMap (\x -> if x == '.' then "foo" else [x]) "example..."
"examplefoofoofoo"
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.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 13 days ago.
Improve this question
somebody care to tell me where the problem with this function is?
Something is wrong with this complex:
buildBoard :: String -> Board
buildBoard xs = buildBoard' ("+" ++ xs ++ "+") []
buildBoard' :: String -> [Cell] -> Board
buildBoard' [] _ = [[]]
buildBoard' xs result
|head xs == ',' && xs!!1 == ',' = buildBoard' (tail xs) (Empty:result)
|head xs == 'w' =
buildBoard' (drop (getFirstNonNumber 0) xs) (Piece White intConversion : result)
|head xs == 'b' =
buildBoard' (drop (getFirstNonNumber 0) xs) (Piece White intConversion : result)
|head xs == '/' && xs!!1 == ',' = buildBoard' (tail xs) (Empty:result)
|head xs == ',' && xs!!1 == '/' = buildBoard' (tail xs) (Empty:result)
|head xs == '+' && xs!!1 == ',' = buildBoard' (tail xs) (Empty:result)
|head xs == '+' && xs!!1 `elem` ['b','w'] = buildBoard' (tail xs) result
|head xs == ',' && xs!!1 == '+' = buildBoard2 (reverse (Empty:result))
|head xs == '+' = buildBoard2 (reverse result)
|otherwise = buildBoard2 (reverse result)
where intConversion = read [xs!!1..xs!!(getFirstNonNumber 0 -1)] :: Int
getFirstNonNumber num = if xs!!num `elem` [',','/'] then num else getFirstNonNumber num+1
separate :: Int -> [a] -> [[a]]
separate _ [] = []
separate n l
| n > 0 = take n l : separate n (drop n l)
| otherwise = []
buildBoard2 :: [Cell] -> Board
buildBoard2 = separate 9
some additional info about what Cell, Board etc is:
data Player = Black | White deriving Show
data Cell = Piece Player Int | Empty deriving Show
data Pos = Pos { col :: Char, row :: Int } deriving Show
type Board = [[Cell]]
Here, at least, is one:
getFirstNonNumber num = if ... then num else getFirstNonNumber num+1
You almost certainly meant that last call to be:
getFirstNonNumber (num+1)
How do i split a list in Haskell, for example, "222 33244" into ["222","33","2","444"] only through recursion and fuctions on the prelude?
My current attempt is:
list xs
|length xs == 0 = ""
|otherwise = listSplit xs
listSplit (x:xs)
|x == head xs = x : ListSplitNext x xs
|otherwise = x:[]
listSplitNext a (x:xs)
|a == x = a : listSplitNext x xs
|otherwise = listSplit xs
So since I don't quite understand your approach and ghci lists 18 compile errors in your code, I'm afraid I can't help you with your attempt at a solution.
As pointed out in a comment, a possible solution would be:
listSplit xs = listSplit' [] (filter (`elem` ['0'..'9']) xs)
listSplit' ws (x:xs) = listSplit' (ws ++ [x : takeWhile (==x) xs]) (dropWhile (==x) xs)
listSplit' ws [] = ws
Filter every element of the string that is not a number (Data.Char.isNumber would do this, too, but the premise was to only use Prelude functions) and call listSplit' on the filtered list.
(ws ++ [x : takeWhile (==x) xs]) collects everything in xs until it reaches a letter that does not equal x, wraps this in a list and appends it to ws.
(dropWhile (==x) xs) removes every letter in xs until it reaches a letter that does not equal x.
Finally, the function calls itself with the updated ws and the reduced xs
If there are no more remaining elements, the function returns ws
If your goal is to use very few pre-defined functions this might give you some ideas:
listSplit :: String -> [String]
listSplit xs =
let (as, a) = foldr go ([], []) numbers
in a : as
where
isNumber x = x `elem` ['0'..'9']
numbers = filter isNumber xs
go cur (res, []) = (res, [cur])
go cur (res, lst#(a:_))
| a == cur = (res, a : lst)
| otherwise = (lst : res, [cur])
Of course you can replace foldr with your own recursion as well:
numberSplit :: String -> [String]
numberSplit xs =
let numbers = filter (`elem` ['0'..'9']) xs
in listSplit numbers
listSplit :: Eq a => [a] -> [[a]]
listSplit =
reverse . go [] []
where
go acc as [] = as : acc
go acc [] (x:xs) = go acc [x] xs
go acc as#(a:_) (x:xs)
| a == x = go acc (a : as) xs
| otherwise = go (as : acc) [x] xs
I had a moment to implement this but I think this is what you're looking for.
listSplit s = go filtered
where filtered = [c | c <- s, elem c ['0'..'9']]
go [] = []
go (x:xs) = (x : takeWhile (== x) xs) : (go $ dropWhile (== x) xs)
Hi i am trying to do a function input is a list of strings, and the output is again a list of all words occurring in the input.
for example input ["For example,", "love,", "hate."]
output ["For","example","love","hate"]
atm i have this. Any help would be appreciated. Also how can i remove the blank space with just one function and in linear time?
And not using any existing function
split' :: String -> [String]
split' [] = []
split' (x:xs)
| isBlank x = split' xs
| otherwise = waitForBlank (x:xs) : split' (drop (length (waitForBlank (x:xs))) xs)
isBlank :: Char -> Bool
isBlank x = if x == ' ' then True else False
waitForBlank :: String -> String
waitForBlank [] = []
waitForBlank (x:xs)
| isBlank x = []
| otherwise = x : waitForBlank xs
There's a cool one-line to perform what you need
["For example,", "love,", "hate."] >>= words
>>= has type (>>=) :: Monad m => m a -> (a -> m b) -> m b, which takes a function which returns a monadic structure and joins the result into the monadic structure.
If you want to implement words by yourself:
words' xs =
let
waitForBlank (acc, buff) [] = (acc ++ [buff], buff)
waitForBlank (acc, buff) (x:xs) =
if x == ' ' then
waitForBlank (acc ++ [buff], []) xs
else
waitForBlank (acc, buff ++ [x]) xs
in
fst (waitForBlank ([], []) xs)
Or with using (:) and reverse the result (for better performance):
words'' xs =
let
waitForBlank (acc, buff) [] = (reverse (buff : acc), buff)
waitForBlank (acc, buff) (x:xs) =
if x == ' ' then
waitForBlank ((reverse buff) : acc, []) xs
else
waitForBlank (acc, x:buff) xs
in
fst (waitForBlank ([], []) xs)
I want to double every second element of a list. Here is the code-
doubleSec n [] = []
doubleSec n (x:xs)
| n==1 = x*2 : doubleSec 0 xs
| otherwise = x : doubleSec 1 xs
doubleSecond xs =
doubleSec 0 xs
How can I compact this logic in a single function?
You can match a pattern on the list like this
doubleSec :: [Int] -> [Int]
doubleSec [] = []
doubleSec [x] = [x]
doubleSec (x : y : xs) = x : 2* y : doubleSec xs
letting you do specific things to the second element
How about this
doubleSecond xs = map (\(x,i) -> if odd i then x*2 else x) (zip xs [0..])
This method will preserve the O(n) running time:
doubleSecond xs =
[ if isOddStep then 2 * x else x |
(isOddStep, x) <- zip (cycle [False, True]) xs ]
An more succinct version by #DavidFletcher:
doubleSecond = zipWith ($) (cycle [id, (2*)])
or:
doubleSecond = zipWith id (cycle [id, (2*)])
as suggested by #Carl.
My task is to re-implement this function
divn :: Integer -> [Integer] -> [Integer]
divn _ [] = []
divn n (x:xs) | mod x n == 0 = x : divn n xs
| otherwise = divn n xs
using 'foldr'.
What I did:
divn' _ [] = []
divn' n (x:xs) = foldr (\x -> if (mod x n == 0) (x:) ([]++)) [] xs
I thought this would work. Actually it doesn't even compile, but says: "Parse error on input ")".
As I didn't find any errors, I decided to re-write if as if' an now its working...
if' True x _ = x
if' False _ x = x
divn' _ [] = []
divn' n (x:xs) = foldr (\x -> if' (mod x n == 0) (x:) ([]++)) [] xs
Does anyone know where's the error?
Thanks!
if needs a then and an else in Haskell,
(\x -> if (mod x n == 0) (x:) ([]++))
should be
(\x -> if (mod x n == 0) then (x:) else id)
Apart from what Daniel Fischer said, you don't need any separate cases: there's no recursion, the empty list case will be handled by foldr. In your code, the first x is always ignored! Correct is
divn' n xs = foldr (\x -> if x`mod`n == 0 then (x:) else id) [] xs
or, by η-reduction,
divn' n = foldr (\x -> if x`mod`n == 0 then (x:) else id) []
Of course, it would be far more idiomatic to simply do
divn'' n = filter ((==0) . (`mod`n))