Reputation: 5086
Evening,
This is my attempt at an equivalent of "str_replace" in Haskell
strReplace :: (Char, Char) -> String -> String -> String {- Original (y) Parsed (z) -}
strReplace _ "" y = y
strReplace x y z = if (y !! 0) == fst x then strReplace x (drop 1 y) (z:([snd x])) else strReplace x (drop 1 y) (z:(y!!0))
Essentially, the first Tuple is the char to be substitued (Ie ('A', 'B') replaces all As to Bs, the second parameter is the String to be parsed and the third parameter should always be left an empty string. Compiler returns
*** Expression : z : [snd x]
*** Term : z
*** Type : [Char]
*** Does not match : Char
Ideas? :)
Upvotes: 0
Views: 172
Reputation: 4843
z is of type [Char]
. You can't use :
to cons a [Char]
into a [Char]
- look at the type signature for :
. You would have to use ++
to append one [Char]
to another.
Additional points:
strReplace
to have a signature :: Char -> Char -> String -> String -> String
.:: a -> a -> [a] -> [a] -> [a]
let
or where
).foo x y = if (y == ... ) ... else ...
it can almost always be improved by either pattern matching or guards.To expand on point 4, you could rewrite that third line as
strReplace x y z | y !! 0 == fst x = ...
| otherwise = ...
Even better, if you took my advice in point 1 and split the tuple into two simple Char
parameters, you could do this:
strReplace x1 x2 y@(y1:ys) z | x1 == y = ...
| otherwise = ...
Upvotes: 1
Reputation: 53901
The problem with your code is that z : [snd x]
is incorrect, z
is a list but :
wants it to be an element. This can be fixed by using z ++ [snd x]
.
If seeing the type signatures helps
(:) :: a -> [a] -> [a]
(++) :: [a] -> [a] -> [a]
Or in your specific case
(:) :: Char -> String -> String
(++) :: String -> String -> String
If I may suggest a few improvements to your code however, first strReplace
shouldn't force you to pass an empty string
strReplace :: (Char, Char) -> String -> String
Next, we can do this two ways, using higher order functions or explicit recursion.
-- recursion
strReplace _ "" = "" -- Base case
strReplace (a, b) (c:cs) | a == c = b : strReplace (a,b) cs
| otherwise = c : strReplace (a, b) cs
So here if the string is empty we're done, otherwise we pattern match, if the first character is the one to be replaced, we replace it and recurse, otherwise we don't replace it and recurse.
This can actually be done much more cleanly with map
though
strReplace (a, b) s = map (\c -> if c == a then b else c) s
This works identically to our previous version, but map
abstracts out the looping logic.
Upvotes: 1