How to remove space from a String? - haskell

I'm trying to do removing space (" ") from a string without using the strip function. How to implement if 'head' == " " (space) in the program?
skipSpaces :: (Eq a) => [a] -> [a]
skipSpaces [] = []
skipSpaces (h:t)
| h `elem` " " = skipSpaces t -- condition if 'head' is equal to " "(space),do nothing.
| otherwise = h : skipSpaces t -- produce the result
I don't know how to declare aboutif 'head' == " " (space)
nor if 'head' == "(contain_strings)"(a collection of letters)".
Example:
Input: "I am twenty one"
Output Expectation: "Iamtwentyone"

You can match the space directly:
skipSpaces [] = []
skipSpaces (' ':t) = skipSpaces t
skipSpaces (h:t) = h : skipSpaces t
One trick, though, is to think about what function to apply to skipSpaces t, depending on the value of h. Consider a slight modification of the above:
skipSpaces [] = []
skipSpaces (' ':t) = id (skipSpaces t)
skipSpaces (h:t) = (h :) (skipSpaces t)
Note the similarity between the last two cases. We can factor out the recursive call as follows:
skipSpaces [] = []
skipSpaces (h:t) = (if h == ' ' then id else (h :)) (skipSpaces t)

Related

Need help in subproblem of parser for polynomials (Haskell)

I'm currently doing an assignment for college where we are implementing an polynomial calculator in Haskell.
The first part of the assignment is doing poly operations, and that is already done.
We get extra credit if we implement an parser for the polynomial, which I'm currently doing by turning a string to a tuple of [(factor, [(variable, exponent)])].
This means "-10y^4 - 5z^5" => "[(-10, [('y', 4)]), (-5, [('z', 5)].
The sub-problem I'm having trouble with is when I encounter polynomials like "5xy^2z^3" that should be stored as [(5, [('x',1), ('y', 2),('z',3)]], I don't know how to parse it.
Any suggestion on how I could approach this?
Thank you in advance for your help!
-- Slipts lists by chosen Char, only used with '+' in this project
split :: Char -> String -> [String]
split _ "" = []
split c s = firstWord : (split c rest)
where firstWord = takeWhile (/=c) s
rest = drop (length firstWord + 1) s
-- Remove all spaces from a string, for easier parsing
formatSpace :: String -> String
formatSpace = filter (not . isSpace)
-- Clever way to parse the polynomial, add an extra '+' before every '-'
-- so after we split the string by '+', it helps us keep the '-'
simplify_minus :: String -> String
simplify_minus [] = ""
simplify_minus (x:xs)
| x == '^' = x : head xs : simplify_minus (tail xs)
| x == '-' = "+-" ++ simplify_minus xs
| otherwise = x : simplify_minus xs
-- Splits an String by occurrences of '+' and creates a list of those sub-strings
remove_plus :: String -> [String]
remove_plus s = split '+' s
-- Removes multiplication on substrings
remove_mult :: [String] -> [[String]]
remove_mult [] = []
remove_mult (x:xs) = (remove_power (split '*' x)) : remove_mult xs
-- Function used to separate a variable that has an power. This translates ["y^2] to [["y", "2"]]
remove_power :: [String] -> [String]
remove_power [] = []
remove_power (x:xs) = (split '^' x) ++ remove_power xs
-- Wrapper function for all the functions necessary to the parser
parse_poly :: String -> [(Integer, String, Integer)]
parse_poly [] = []
parse_poly s = map (tuplify) (rem_m (remove_plus (simplify_minus (formatSpace s))))
rem_m :: [String] -> [String]
rem_m l = map (filter (not . (=='*'))) l
helper_int :: String -> Integer
helper_int s
| s == "" = 1
| s == "-" = -1
| otherwise = read s :: Integer
helper_char :: String -> String
helper_char s
| s == [] = " "
| otherwise = s
tuplify :: String -> (Integer, String, Integer)
tuplify l = (helper_int t1, helper_char t3, helper_int (drop 1 t4))
where (t1, t2) = (break (isAlpha) l)
(t3, t4) = (break (=='^') t2)
main :: IO()
main = do
putStr("\nRANDOM TESTING ON THE WAE\n")
putStr("--------------\n")
print(parse_poly "5*xyz^3 - 10*y^4 - 5*z^5 - x^2 - 5 - x")
-- [(5,"xyz",3),(-10,"y",4),(-5,"z",5),(-1,"x",2),(-5," ",1),(-1,"x",1)]
``
You have pretty much everything there already, but you do need to use break recursively to grab everything until the next variable. You probably should also use the similar span to first grab the coefficient.
parsePositiveMonomial :: String -> (Integer, [(Char, Integer)])
parsePositiveMonomial s = case span isDigit s of
([], varPows) -> (1, parseUnitMonomial varPows)
(coef, varPows) -> (read coef, parseUnitMonomial varPows)
where parseUnitMonomial [] = []
parseUnitMonomial (var:s') = case break isAlpha s' of
...

Haskell string/output manipulation

I do have the following code:
suffixes :: [a] -> [[a]]
suffixes [] = [[]]
suffixes l#(_:t) = l : suffixes t
prefixes :: [a] -> [[a]]
prefixes [] = [[]]
prefixes l#x = l : prefixes (init x)
menu :: Char -> [a] -> Either String [[a]]
menu 'p' l = Right (prefixes l)
menu 's' l = Right (suffixes l)
menu x _ = Left ("(" ++ show x ++ ")" ++ "is not supported, use (p)refix or (s)uffix")
I do have the following test function:
testMenuP = "Expected Right [[1,2],[1],[]]; menu 'p' [1,2] returned " ++ show (menu 'p' [1,2] :: Either String [[Int]])
testMenuS = "Expected Right [[1,2],[2],[]]; menu 's' [1,2] returned " ++ show (menu 's' [1,2] :: Either String [[Int]])
testMenuC = "Expected Left \"(d) is not supported, use (p)refix or (s)uffix\"; menu 'd' [1,2] returned " ++ show (menu 'd' [1,2] :: Either String [[Int]])
testMenu = putStr (testMenuP ++ "\n" ++ testMenuS ++ "\n" ++ testMenuC ++ "\n")
My question is now, how do I get rid of the quotes '' in the Char 'd' when I output the string (as shown in the test function testMenuC).
You can replace the part of menu with:
menu x _ = Left ("(" ++ [x] ++ ")" ++ "is not supported, use (p)refix or (s)uffix")
or even
menu x _ = Left . mconcat $ ["(", [x], ")", "is not supported, use (p)refix or (s)uffix"]

Haskell :improve list union

I want to create a union function for two images (created using lists of type string.) I have started by creating a unionList function that combines two lists.
unionList :: String -> String -> String
unionList xs ys = xs ++ foldl (flip delete) ys xs
This works but not how i want it too.
I want it to work like:
input = unionList [’ ’,’ ’,’X’,’X’,’ ’] [’X’,’ ’,’X’,’ ’,’X’]
output = "X XXX"
any ideas on how it's done to achieve this.
EDIT: I'm ultimately trying to create a union of two images.
image 1 = [" XX ", image 2 = ["XX XX", type Img = [String]
" X X ", " X ",
" XX "] "XX XX"]
^
examples
Input = (imgUnion (image 1) (image 2))
should give me the union of the two images.
imgUnion defined as
imgUnion :: Img -> Img -> Img
There are probably better ways to do this, but I had some fun trying out a couple of methods.
Pattern matching on list head item:
unionList1 :: String -> String -> String
unionList1 ('X':xs) ( _ :ys) = 'X' : unionList1 xs ys
unionList1 ( _ :xs) ('X':ys) = 'X' : unionList1 xs ys
unionList1 ( _ :xs) ( _ :ys) = ' ' : unionList1 xs ys
unionList1 _ _ = []
Guards!
unionList2 :: String -> String -> String
unionList2 (x:xs) (y:ys)
| x == ' ' = y : rest
| y == ' ' = x : rest
| otherwise = x : rest
where rest = unionList2 xs ys
unionList2 _ _ = []
And a solution as proposed with zipWith:
unionList3 :: String -> String -> String
unionList3 = zipWith (\x y -> if x /= ' ' then x else y)
You can then use one of these union functions on the image:
imgUnion :: [String] -> [String] -> [String]
imgUnion = zipWith unionList3
main :: IO ()
main = do
let img1 = [" XX ",
" X X ",
" XX "]
img2 = ["XX XX",
" X ",
"XX XX"]
mapM_ putStrLn (imgUnion img1 img2)
Gives as output:
XXXXX
XX X
XXXXX

Foldl on string

I would like to foldl a string so that any occurrence of zero which is preceded by # is replaced with "k". So "a.#0.1.2.0" becomes, "a.#k.1.2.0". 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)) "" "a.#0.1.2.0"
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?
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
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).

Remove all vowels of a string with recursive function

I can remove the vowels without a recursive function like this:
NoVowels:: String -> String
NoVowels xs = filter f xs where f x = not (x == ’a’ || x == ’e’ || x == ’i’ || x == ’o’ || x == ’u’)
But how may I do that with a recursive function ?
I tried something like this but of course did not work (parse Error):
NoVowels :: String -> String
NoVowels "" = error "Empty String!!"
NoVowels (x:xs)
| x in (x == 'a'|| x == 'e' || x == 'i' || x == 'o' || x == 'u') = NoVowels (tail x)
If the head is a vowel then I CUT it from the string and pass recursively the tail, if its not a vowel how may I verify the other string without removing it.
Update obs: I want to return the function without the vowels.
I thins it makes sense to define a function isVowel :: Char->Bool and after that write something like this :
noVowels :: String -> String
noVowels [] = []
noVowels (x:xs)
|isVowel x = noVowels xs
|otherwise = x : noVowels xs
If you don't want to define one more function you can try next code :
noVowels :: String ->String
noVowels [] = []
noVowels (x:xs)
|not( x `elem` "aeiou") = x: noVowels xs
|otherwise = noVowels xs
Here's a bit of an improvement on the code. Just in case you missed out on preserving the cases involved.
module Disemvowel where
disemvowel :: String -> String
disemvowel [] = []
disemvowel " " = " "
disemvowel (x:xs)
| x `elem` "aeiouAEIOU" = disemvowel xs
| otherwise = [x] ++ disemvowel xs

Resources