Haskell - error in find/replace function - haskell

i'm making a function that takes three string values w1, w2 and s, and returns s but with all occurrences of the string w1 replaced by w2.
i have finished it, but there is an error. if w1 is only in the string s once, it works fine. but if it occurs multiple times, it doesn't work. eg:
Main> swapwords "turtles" "goats" "more turtles are becoming blind"
"more goats are becoming blind"
swapwords "turtles" "goats" "the blue turtles, dislike the green turtles"
"the blue turtles, dislike the green goats"
here is the current code:
split :: String -> Char -> String -> [String]
split "" _ "" = []
split "" _ r = [r]
split (x:xs) c ""
| x == c = [[c]] ++ split xs c ""
| otherwise = split xs c [x]
split (x:xs) c r
| x == c = r : [[c]] ++ split xs c ""
| otherwise = split xs c (r ++ [x])
swap :: String -> String -> [String] -> [String]
swap a b [] = []
swap a b (x:xs)
|x==a = [b] ++ xs
|x/=a = [x] ++ swap a b (xs)
join :: [String] -> String
join [] = ""
join (x:xs) = x ++ join (xs)
swapwords :: String -> String -> String -> String
swapwords a b "" = []
swapwords a b c = join (swap a b d)
where d = split c ' ' []
if anybody knows the solution it would help me loads. thanks

Your error is here:
swap :: String -> String -> [String] -> [String]
swap a b [] = []
swap a b (x:xs)
|x==a = [b] ++ xs -- <<< here
|x/=a = [x] ++ swap a b (xs)
When you find the word ayou are replacing it with b, but then you want to continue swapping on the remainder of the list.

Related

Is there a way to get a 'split' function in Haskell to accept two different types of input?

I am trying to create a function split that can take either [Int] and Int or [Char] Char to split either a list of integers on an integer given or split a string on a character given. I.e.
Main> split [1,2,3,0,4,5,0,0,7,8,9] 0
[[1,2,3],[4,5],[7,8,9]]
Main> split "Mary had a little lamb" ' '
["Mary","had","a","little","lamb"]
I've tried using Either and (Eq a) but it still doesn't seem to work. Below is what I've tried doing using class instances but I know very little about this and get the error Haskell 98 does not support multiple parameter classes.
The best way I think I'd understand it would be to use pattern matching or list comprehensions. Any help much appreciated.
class Split a where
split :: (Eq a) => [a] -> a -> [a]
instance Split [Char] Char where
split [] c = [""]
split (x:xs) c
| x == c = "" : (split xs c)
| otherwise = (x : head (split xs c)) : tail (split xs c)
instance Split [Int] Int where
split [] n = []
split (x:xs) n
| x == n = [] : (split xs n)
| otherwise = (x : head (split xs n)) : tail (split xs n)
I can get the split function to work with strings and characters but not lists of integers.
You need a polymorphic function split
split :: (Eq a) => [a]->a->[[a]]
Implementation is simple
split [] _ = [[]]
split (x:xs) c
| x == c = [] : (split xs c)
| otherwise = (x : head subSplit) : tail subSplit
where
subSplit = split xs c
EDIT
I suggest different implementation.
split :: Eq a => [a] -> a -> [[a]]
split x c = map reverse $ split' x c []
where
split' :: Eq a => [a] -> a -> [a] -> [[a]]
split' [] _ a = [a]
split' (x:xs) c a
| x == c = a : split' xs c []
| otherwise = split' xs c (x:a)
Just to contribute with an other approach. This solution uses foldr. I think it is quite neat but less undestable than #talex's
split :: (Eq a) => [a] -> a -> [[a]]
split l c = foldr f acc l
where acc = [[]]
f a t#(i#(x:_):xs) = if a == c then []:t else (a:i):xs -- Case when the current accumulator is not empty
-- | |- cons a to current accumulator
-- |- start a new accumulator
f a t#([]:xs) = if a == c then t else [a]:xs -- Case when the current accumulator is empty. Usefull when two separators are together
-- | |- cons a to current accumulator
-- |- Don't start a new accumulator, just continue with the current
Just correct solution.
split :: Eq a => [a] -> a -> [[a]]
split xs delim = go $ dropWhile (== delim) xs
where
go [] = []
go xs = let (tok, rest) = break (== delim) xs
in tok : go (dropWhile (== delim) rest)
Data.List.Split.splitOn (available from the split package) is close:
> splitOn [0] [1,2,3,0,4,5,0,0,7,8,9]
[[1,2,3],[4,5],[],[7,8,9]]
> splitOn " " "Mary had a little lamb"
["Mary","had","a","little","lamb"]
Your split :: Eq a => [a] -> a -> [[a]] would be
split lst d = filter (not.null) $ splitOn [d] lst

Haskell: Efficient accumulator

What is the best way to map across a list, using the result of each map as you go along, when your result is of a different type to the list.
for example
f :: Int -> Int -> String -> String
l = [1,2,3,4]
I would like to have something that walks along the list l and does:
f 1 2 [] = result1 => f 2 3 result1 = result2 => f 3 4 result3 ==> return result3.
I can sort of get this to work with a an accumulator, but it seems rather cumbersome. Is there a standard way to do this... or is this something for Monads??
Thanks!
NB the function above is just for illustration.
This is just a fold left over the pairs in the input list:
f :: Int -> Int -> String -> String
f = undefined
accum :: [Int] -> String
accum xs = foldl (flip . uncurry $ f) "" $ zip xs (drop 1 xs)
You probably want to use Data.List.foldl' instead of foldl, but this is an answer that works with just Prelude.
Seems like a job for fold:
func f l = foldl (\s (x, y) -> f x y s) "" (zip l (tail l))
-- just some placeholder function
f :: Int -> Int -> String -> String
f x y s = s ++ " " ++ show(x) ++ " " ++ show(y)
l = [1,2,3,4]
main = print $ func f l
prints:
" 1 2 2 3 3 4"
(if you can change the signature of f, you can get rid of the ugly lambda that rearranges arguments)
Of course, rather than zipping, you could pass along the previous element inside the fold's accumulator. For example:
l = [1,2,3,4]
f x y = (x,y)
g b#(accum,prev) a = (accum ++ [f prev a],a)
main = print (foldl g ([],head l) (tail l))
Output:
([(1,2),(2,3),(3,4)],4)

recursive repetition of a string

I am trying to write a function that will take 2 strings, p and k. It will check the lengths of p and k and repeat the letters in p consecutively until the result word is of the length of k. ex: Let p = 123 and k = 45678. Then result word = 12312, because length of k is 5. So the chars of p are consecutively repeated until end word reaches length of k. My code below does not work as I want it to:
repString::[Char]->[Char]->[Char]
repString [] (y:ys) =[]
repString (x:xs) [] =[]
repString (x:xs) (y:ys)
|length(x:xs)<length(y:ys) =(x:xs)++x:repString (xs) []
main = do
print $ repString "123" "45678"
I am not sure how to make this work, because every time it reaches the end of x:xs, it will see an empty string and then it will fulfill the appropriate base case and terminate. I don't know how to make it go back to the beginning of (x:xs) and start printing again.
What you're trying to write is something like:
repString :: [Char] -> [Char] -> [Char]
repString [] k = []
repString p [] = []
repString p k
| length p <= n = p ++ repString p (drop (length p) k)
| otherwise = take n p
where n = length k
But would be better written as:
repString :: [Char] -> [Char] -> [Char]
repString p k = take (length k) (cycle p)

Valid Parenthese in a string (Haskell implementation)

the problem is to check whether parentheses in a string is properly closed or not. For Haskell implementation, so far I have following. It looks quite awkward. I am looking for a more "Haskell-style" or more elegant implementation.
import Data.List
isValidParentheses :: String -> Bool
isValidParentheses = isValidHelper . (filter isParenthese)
getIndex :: (Eq a) => a -> [a] -> Int
getIndex c xs = getOut (elemIndex c xs)
where getOut (Just x) = x
getOut Nothing = -1
isLeftParenthese :: Char -> Bool
isLeftParenthese c = (getIndex c "{[(") /= -1
isRightParenthese :: Char -> Bool
isRightParenthese c = (getIndex c "}])") /= -1
isParenthese :: Char -> Bool
isParenthese c = isLeftParenthese c || isRightParenthese c
isValidHelper :: String -> Bool
isValidHelper xs = helper xs []
where helper (x:xs) [] | isRightParenthese x = False
| otherwise = helper xs [x]
helper [] st = null st
helper (x:xs) (s:ss) | isLeftParenthese x = helper xs (x:s:ss)
| ((getIndex x "}])") /= (getIndex s "{[(")) = False
| otherwise = helper xs ss
Thanks
Loop through the string
Store opening parentheses in stack
Pop matching parentheses out of the stack
Check if stack is empty at the end
isValid = loop []
where
match '(' ')' = True
match '{' '}' = True
match '[' ']' = True
match _ _ = False
loop st [] = null st
loop st (x:xs)
| x `elem` "([{" = loop (x:st) xs
| x `elem` ")]}" = case st of
open : st' | match open x -> loop st' xs
_ -> False -- unmatched close
| otherwise = loop st xs

how can i count prefixes in haskell?

I want to create a function in haskell, that returns the number of times a single word is a prefix of a list of words. For example: for the word "go" and the list of words ["ace","going", "gone", "golf"], it should return 3. What I have so far is this:
numberOfPrefixes _ [] = error ("Empty list of strings")
numberOfPrefixes [] _ = error ("No word")
numberOfPrefixes (x:xs) (y:ys)
| isPrefixOf (x:xs) y = 1 + numberOfPrefixes(x:xs) ys
| otherwise = 0
But this only works if the first element of the list of words is actually a prefix. If the first element is not a prefix, the whole thing falls apart. Any help making this right?
isPrefixOf :: (Eq a) => [a] -> [a] -> Bool
isPrefixOf [] _ = True
isPrefixOf _ [] = False
isPrefixOf (x:xs) (y:ys) = x == y && isPrefixOf xs ys
Here's how I'd write this
(.:) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
(.:) = (.) . (.) -- A common utility definition
infixr 9 .:
prefixCount :: Eq a => [a] -> [[a]] -> Integer
prefixCount = length .: filter . isPrefixOf
Or writing it pointfully
prefixCount l ls = length $ filter (isPrefixOf l) ls
If you really want to write it recursively
prefixCount l [] = 0
prefixCount x (l:ls) | <is prefix?> = 1 + prefixCount x ls
| otherwise = prefixCount x ls
and just fill in <is prefix?> with a check whether x is a prefix is of l

Resources