Replace default value with another default value Haskell - 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

Related

Haskell: for every even appearance in an array, concatenate an int to the final list

I'm currently trying to write a function that takes as arguments an Int and an array of Ints and for every even value in the array, it concatenates the Int to the final array.
So, something like this:
f 3 [1,2,3,4,5,6] = [1,2,3,3,4,3,5,6,3]
This is the code I imagined would work (I'm just beginning so sorry if it's bad):
f :: Int -> [Int] -> [Int]
f(x,[]) = []
f(x,y)
|even head(y) = (head(y) ++ [x] ++ f(x,drop 1 y)
|otherwise = head(y) ++ f(x,(drop 1 y))
The error I'm getting is "Couldn't match expected type of 'Int' with actual type (a3, [[a3]])'. I understand the parameters types are mismatched, but I'm not sure how a proper syntax would look like here
You use (x, []), so that means the input type would be a tuple, so f :: (Int, [Int]) -> [Int].
I would also use pattern matching instead of head and tail, so:
f :: Int -> [Int] -> [Int]
f _ [] = []
f x (y:ys)
| even y = y : x : f x ys
| otherwise = y : f x ys
You can also generalize the type signature, and work with an inner function to avoid passing the x each time:
f :: Integral a => a -> [a] -> [a]
f x = go
where go [] = []
go (y:ys)
| even y = y : x : go ys
| otherwise = y : go ys
Another way of looking at this would be using a right fold to insert the desired element after even numbers.
f :: Int -> [Int] -> [Int]
f x lst = foldr (\y i -> if even y then y:x:i else y:i) [] lst
Which we can simplify to:
f :: Int -> [Int] -> [Int]
f x = foldr (\y i -> if even y then y:x:i else y:i) []
Note that without specifying the type, the more general inferred type of f would be:
f :: (Foldable t, Integral a) => a -> t a -> [a]

How can I fix my replace haskell function?

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

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?

Parse error due to incorrect indentation or mismatched brackets can't solve

So I am trying to create my own split function in Haskell and I keep getting a parse error but I can't figure out exactly why it is doing it
split :: Eq a => a -> [a] -> [[a]]
split _ [] = []
split x y = let
test :: Eq a => a -> [a] -> [a]
test x [] = []
test x (y:ys) | x == y = []
| otherwise = y : (test x ys)
Your let ... in expression is missing the in part.

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

Resources