Reputation: 1025
I would like to foldl a string so that any occurrence of zero which is preceded by @ is replaced with "k". So "[email protected]" becomes, "[email protected]". How do I do that? So far my attempt is
test = foldl(\x acc-> if((last acc) == "@" && x == "0" then acc ++ "k" else acc ++ x)) "" "[email protected]"
However, it doesn't work. Foldl is expecting list of string and what I'm providing is just a string. How do I overcome that?
Upvotes: 3
Views: 2056
Reputation: 48580
Taking chi's advice,
rep "" = ""
rep ('@' : '0' : xs) = "@k" ++ rep xs
rep (x : xs) = x : rep xs
If we want to get fancier,
rep = snd . mapAccumL go False
where
go True '0' = (False, 'k')
go _ '@' = (True, '@')
go _ x = (False, x)
or even
rep = snd . mapAccumL go 'x'
where
go '@' '0' = ('0', 'k')
go _ y = (y, y)
To use foldr
with this second approach (just because it's shorter; the first will work fine too, and allows generalization),
rep xs = foldr go (const "") xs 'x'
where
go '0' r '@' = 'k' : r '0'
go x r _ = x : r x
To use zipWith
(which is more awkward to generalize):
rep xs = zipWith go ('x' : xs) xs where
go '@' '0' = 'k'
go _ x = x
Upvotes: 8
Reputation: 77941
As others have commented, foldl
would not fit well for this task. However, using the idea of difference list, you may still do this efficiently using foldl
:
repl :: String -> String
repl a = foldl loop id a ""
where
loop :: (String -> String) -> Char -> (String -> String)
loop f '@' ('0':rest) = f ('@':'k':rest)
loop f x xs = f (x:xs)
Just for the purpose of demonstration and the fact that the question has asked for a foldl
solution. (not that I would recommend doing it this way).
Upvotes: 2