Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - Does a replace function exist?

I have to make three functions for replacing of flat strings and in lists.

I don't know, whether there is a replace function like in other languages. I searched for that however unfortunately without success :-(

So my attempt is yet quite thin.

1st function:

replace  ::  String  ->  String  ->  String  ->  String
replace findStr replaceStr myText = replace()??

My approach for the 1st function:

replace :: String -> String -> String -> String
replace [] old new = []

replace str old new = loop str
  where
    loop [] = []
    loop str =
      let (prefix, rest) = splitAt n str
      in
        if old == prefix                -- found an occurrence?
        then new ++ loop rest           -- yes: replace

        else head str : loop (tail str) -- no: keep looking
    n = length old  

2nd function:

replaceBasedIdx ::  String  ->  [String]  ->  String  ->  String
replaceBasedIdx findStr replaceStrList myText = replace()???

This function should replace the 1st findStr in myTxt with the 1st element of replaceStrList, the 2nd findStr with the 2nd element and so on...

Example:

replaceBasedIdx   "a"  ["G","V","X"]  "Haskell is a language"
"HGskell is V lXnguage"

My approach for the 2nd function:

replaceBasedIdx    ::  String  ->  [String]  ->  String  ->  String
replaceBasedIdx    findStr replaceStrList myText = replaceBasedIdxSub findStr replaceStrList myText 0

replaceBasedIdxSub  ::  String  ->  [String]  ->  String  -> Int -> String
replaceBasedIdxSub findStr replaceStrList myText counter = loop myText
  where
    loop [] = []
    loop myText =
      let (prefix, rest) = splitAt n myText
      in
        if findStr == prefix                                -- found an occurrence?
        then (replaceStrList !! (counter+1)) ++ loop rest   -- yes: replace it

        else head myText : loop (tail myText)               -- no: keep looking
    n = length findStr

I'm now very near to the final result, however the counter doesn't increment.

Could you please tell me, where my mistake is? And how could I modifey the 1st or 2nd function to get the 3rd function also?

3rd function:

replaceBasedIdxMultiple  ::  [String]  ->  [String]  ->  String  ->  String
replaceBasedIdxMultiple  findStrList replaceStrList myText = replace()???

This function should replace each element of findStrList in myTxt with the corresponding element from the replaceStrList, so 1. with 1., 2. with 2. and so on...

Example:

replaceBasedIdxMultiple ["A","X","G"] ["N","Y","K"]  "ABXMG"
"NBYMK"

Could you help me with this? some tips and hints, how to begin with it?

I'm really disparate :-(

Thanks a lot in advance

Kind greetings!

like image 925
John Avatar asked Mar 24 '23 01:03

John


2 Answers

replace exists in Data.List.Utils, part of MissingH package.

Actually, it's a really concise implementation:

replace :: Eq a => [a] -> [a] -> [a] -> [a]
replace old new = join new . split old
like image 81
Koterpillar Avatar answered Apr 01 '23 05:04

Koterpillar


First off, join is a bad name as that's already a standard function. Also, I have no idea why you define this function, in this way – it doesn't seem to do anything much useful.

But ok, you did try something. So let's now find a proper solution...

As is usually a good idea in Haskell, we want to break this up into sub-problems. What's first needed is to find the sub-strings you'd like to replace. This could look something like

locateSub :: (Eq a) =>
        [a]             -- ^ The sought sublist.
     -> [a]             -- ^ The source list.
     -> Maybe ([a],[a]) -- ^ Everything to the left and, if found, everything
                        -- to the right of the sought sublist. No need to return
                        -- the sublist itself in between since we already know it!

Using this function, replace is straight-forward:

replace oldSub newSub list
    = case locateSub oldSub list of
        Nothing -> list   -- Sublist not found: we're done already!
        Just (l, r) -> l ++ newSub ++ replace oldSub newSub r

replaceBasedIdx isn't much more difficult, you only need to recurse over a list of newSubs rather than passing it always as-is.

So what you need to do is implement locateSub. With isPrefixOf you're already on the right track. Actually it looks a lot like your _replace (BTW: it's custumary in Haskell to use the prime ' rather than underscores to name "local variants / helpers" of a function, so you'd rather call it replace'.)

like image 35
leftaroundabout Avatar answered Apr 01 '23 03:04

leftaroundabout