How can I fix my replace haskell function? - haskell

It eill work when : replace :: Eq a => a -> a -> [a] -> [a] will be. How can I convert az a to an [a] in my code ?
replace :: Eq a => a -> [a] -> [a] -> [a]
replace _ _ [] = []
replace a x (y:ys)
| a == y = x : replace a x ys
| otherwise = y : replace a x ys
Example:
replace '?' "a" "" == ""
replace 'a' "e" "alma" == "elme"
replace 'a' "e" "nincsbenne" == "nincsbenne"

You are using wrong operator for the first guard (a == y) - : is used to prepend a head element to a list but x is a list not a single element, so you need to use ++ which concatenates two lists (x and one returned by recursive call):
replace :: Eq a => a -> [a] -> [a] -> [a]
replace _ _ [] = []
replace a x (y:ys)
| a == y = x ++ replace a x ys -- ++ instead of :
| otherwise = y : replace a x ys
Related - Haskell (:) and (++) differences

Related

sort a list of strings based on the number of occurrences of a given char in the string

I am trying to create a function that will sort a list of strings in ascending order bases on the number of occurrences of a certain character without using any library functions, but i do want to know how i can use my version of inssort to do this i am bit confused any help appreciated
My code so far returns wrong order,
say i give it
sortwords 'c' ["abcc", "abc", "bbc", "aa"]
i want it to return
["aa", "abc", "bbc", abcc"]
but i get
["abc","bbc","aa","abcc"]
Here is my code:
insert :: Ord b => (a -> b) -> a -> [a] -> [a]
insert f a [] = [a]
insert f a (x:xs) = if f a <= f x then a:x:xs else x : insert f a xs
inssort :: Ord b => (a -> b) -> [a] -> [a]
inssort f [] = []
inssort f [x] = [x]
inssort f (x:xs) = insert f x (inssort f xs)
countocc :: Eq a => a -> [a] -> Int
countocc x [] = 0
countocc x xs = length [x' | x' <- xs, x == x']
sortwords :: Char -> [String] -> [String]
sortwords c [] = []
sortwords c [x]= [x]
sortwords c (x:y:ys) = if countocc c x <= countocc c y then x : sortwords c (y:ys) else y : sortwords c (x:ys)
I won't spoil the whole solution, but here's a hint: it looks like you are trying to reimplement your sorting procedure in sortwords. Don't do that; just reuse inssort directly! Try filling in this replacement function skeleton:
sortwords :: Char -> [String] -> [String]
sortwords c strings = inssort f strings where
f s = ...
What do you think the ... should be?

Replace default value with another default value Haskell

I have the following code which works fine
replacePointsWithZeros :: Eq a => a -> a -> [a] -> [a]
replacePointsWithZeros _ _ [] = []
replacePointsWithZeros replacee replacer (x:xs)
| replacee == x = replacer:replacePointsWithZeros replacee replacer xs
| otherwise = x:replacePointsWithZeros replacee replacer xs
but i want to replace the replacee and replacer arguments with default values, so essentially what i want is
replacePointsWithZeros :: Eq a => [a] -> [a]
replacePointsWithZeros [] = []
replacePointsWithZeros (x:xs)
| '.' == x = '0':replacePointsWithZeros xs
| otherwise = x:replacePointsWithZeros xs
However when I try that it complains about the types with a message I dont really understand as I am very new to Haskell. What am I doing wrong and how can i fix it?
Im assuming the issue is in the line
replacePointsWithZeros :: Eq a => [a] -> [a]
and the fact that im using a instead of Char but if I switch a to Char I get an issue with the Eq statement
Since you write '.' == x, this means that x is a Char, and therefore (x:xs) is a list of Chars, so a [Char], or a String.
Furthermore you write '0': and x: as output, hence that means that the output is a list of Chars as well. This thus means that the signature of replacePointsWithZeros is:
replacePointsWithZeros :: String -> String
replacePointsWithZeros [] = []
replacePointsWithZeros (x:xs)
| '.' == x = '0':replacePointsWithZeros xs
| otherwise = x:replacePointsWithZeros xs
You can make the above more lazy by putting the condition in a mapping function:
replacePointsWithZeros :: String -> String
replacePointsWithZeros [] = []
replacePointsWithZeros (x:xs) = f x : replacePointsWithZeros xs
where f '.' = '0'
f x = x
and we can use a map function instead of the explicit recursion:
replacePointsWithZeros :: String -> String
replacePointsWithZeros = map f
where f '.' = '0'
f x = x

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 Nested Loops

I am trying to split a list whenever f returns true, for example:
separate even [1,2,3,4] = [[2],[4]]
Current code:
separate f (x:xs) currentstr finalstr
| f x = (finalstr ++ currentstr) : separate f xs [] finalstr
| otherwise = (currentstr ++ x) : separate f xs (currentstr + x) finalstr
separate f [] currentstr finalstr = []
Can anyone provide some insight on how to fix this? Values for currentstr and finalstr will be provided as [] in another function always, so this is not a concern.
You could divide your problem into the following sub-problems:
Split a list in two where the first sequence is equivalent when applying f to each element:
splitOn :: Eq b => (a -> b) -> [a] -> ([a], [a])
splitOn f [] = ...
splitOn f (x:xs) = ...
For example,
> splitOn odd [1,3,3,4,5]
([1,3,3], [4,5])
Group each element in the list by what f returns:
groupOn :: Eq b => (a -> b) -> [a] -> [[a]]
groupOn f [] = ...
groupOn f xs = ...
For example,
> groupOn odd [1,3,3,4,5,6,8]
[[1,3,3],[4],[5],[6,8]]
You can do this by applying splitOn recursively. Think case-of.
Filter out sub-lists in which the first element satisfies f:
separate :: (a -> Bool) -> [a] -> [[a]]
separate f xs = filter (\ys -> ...) (groupOn f xs)
where ys would be [1,3,3], [4], [5] and [6,8] in the above example.

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