Haskell trying to mutate string in [String] - haskell

movex [] a s = []
movex (x:xs) a s
| elem a x = moveNow x a s
| otherwise = x : (movex xs a s)
where
moveNow x a s
| s == 'l' = moveNow2 x a
where
moveNow2 [] _ = []
moveNow2 (x:y:xs) a
| x == ' ' && y == a = a : x : moveNow2 (y:xs) a
| otherwise = x : moveNow2 (y:xs) a
<- This is what I got right now
I am trying to make a function that iterates through [string], finds the right string and then mutates it.
given input
func ["abc", "dfg"] f l -- move f in this list 1 space left --
expected output
["abc", "fdg"]
Right now I am stuck at movex function that gives me error
Couldn't match expected type `Char' with actual type `[Char]'
In the first argument of `(:)', namely `x'
In the expression: x : (movex xs a s)

Direct solution to the error is to replace the line
| elem a x = moveNow x a s
With
| elem a x = moveNow x a s : movex xs a s
Or, probably
| elem a x = moveNow x a s : xs
Depending on what you want to do after the first match: continue looking for certain character, or leave other strings untouched.
Your moveNow function has return type String, or [Char], while movex has [String], or [[Char]], that's why compiler complains.
To avoid such problems(or fix them easier) consider writing explicit type signatures, like so:
movex :: [String]->String->String->[String]

Related

Error return Haskell

i have some troubles here with this.
I'm trying to do something like that:
Prelude> func ["abacate", "aba", "baaba"]
["cate", "", "ba"]
this exercise, must return words without the substring aba.
elimLetras :: String -> String
elimLetras [] = []
elimLetras (x:y:z:xs)
| elem x "aA" || elem y "bB" || elem z "aA" = elimLetras xs
| otherwise = x : elimLetras (x:xs)
| otherwise = y : elimLetras (y:xs)
| otherwise = z : elimLetras (z:xs)
elimLetras (x:xs) = x:xs
this code it's not working right.
On ghci, i'ts return:
prelude> elimLetras "abacate"
output: "cce"
Any tips?
So you are trying to remove the case insensitive substring aba from a String. Your method of checking for a substring isn't bad. It wouldn't scale very well but you can keep it like this if you want. The main issue is with the multiple otherwise statements. You should only ever have one otherwise statement, as only the first one will ever be reached.
Here is a rewrite of your function with a couple of helper function:
import Data.Char (toLower)
elimLetras :: String -> String
elimLetras (x:y:z:xs)
| stringEquals "aba" [x,y,z] = elimLetras xs
| otherwise = x : elimLetras (y:z:xs)
elimLetras xs = xs -- anything that has fewer than 3 letters is returned "as is".
-- Check if two strings are the same (case insensitive)
stringEquals :: String -> String -> Bool
stringEquals a b = stringToLower a == stringToLower b
stringToLower :: String -> String
stringToLower [] = []
stringToLower (x:xs) = toLower x : stringToLower xs
If you know about the map function, here is how I would probably write it:
elimLetras' :: String -> String
elimLetras' (x:y:z:xs)
| "aba" == map toLower [x,y,z] = elimLetras' xs
| otherwise = x : elimLetras' (y:z:xs)
elimLetras' xs = xs

Haskell string manipulation. Non-exhaustive patterns in function error

I am trying to solve a simple problem on HackerRank and am receiving the error in the title. The problem asks to take in a string and reduce it by removing adjacent pairs of letters. So "aabcdd" => "bc" for example. Here's my code:
main :: IO()
main = do
line <- getLine
putStrLn (reduce' line)
reduce' :: String -> String
reduce' [] = []
reduce' (x0:x1:xs)
| x1:xs == [] = [x0]
| x0 == x1 = reduce' xs
| otherwise = x0 : x1 : reduce' xs
I am confused because I think I have the edge cases covered. I don't want an answer to the problem, I just want to know why I am getting the error. Thanks!
You are not matching the case where you have only one element in the list
reduce' :: String -> String
reduce' [] = []
reduce' [x] = [x]
reduce' (x0:x1:xs)
| x0 == x1 = reduce' xs
| otherwise = x0 : x1 : reduce' xs
This | x1:xs == [] = [x0] is the pattern matching added, so there is no need to check in the guards.

Convert a string to a list of "grades"

I want to make a function that takes in a string of multiple "grades" of varying length and convert it to a list of grades.
Grade is just a data structure that looks like this (just an arbitrary grading system):
data Grade = A+ | A | A- | B+ | B | B- | P | F
deriving (Show, Eq)
As you can see, the grades have varying length. If they had length 1 or consistent length, this would have been much easier.
Here is the function that I want to make:
This is what the string input looks like "PA+FABA+B-A"
stringToGrade :: String -> Grade
stringToGrade stringGrade
| stringGrade == "A+" = A+
| stringGrade == "A" = A
-- and so on
extractGrades :: String -> [Grade]
extractGrades stringGrades = case stringGrades of
[] -> []
x:y:ys
| x == "A" && y == "+" -> [stringToGrade (x : y)] : extractGrades ys
| x == "A" -> [stringToGrade x] : extractGrades y:ys
-- and so on
As you can see, this is not going anywhere.
Is there an elegant and easy way I cam do this instead of had coding everything?
We can apply pattern matching so to match a string prefix. Here's an example:
foo :: String -> [Int]
foo [] = []
foo ('h':'e':'l':'l':'o':rest) = 1 : foo rest
foo ('b':'o':'b':rest) = 2 : foo rest
foo ('b':rest) = 3 : foo rest
foo _ = error "foo: invalid input syntax"
Sample usage:
foo "hellobbobbobhello" ==> [1,3,2,2,1]
You can split the string into tokens using combination of split functions.
split (keepDelimsR $ oneOf "+-") "PA+FABA+B-A"
will create this form, where the suffixes are attached.
["PA+","FABA+","B-","A"]
Now, you can split this further with a custom splitter
splitInit [] = []
splitInit [x] = [[x]]
splitInit [x,y] = [[x,y]]
splitInit (x:xs) = [x] : splitInit xs
a combination will give you
concatMap splitInit $ split (keepDelimsR $ oneOf "+-") "PA+FABA+B-A"
["P","A+","F","A","B","A+","B-","A"]
where you can map through your constructors

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

Haskell passing empty Character to a function

I'm working in Haskell in two functions:
Basically I want to get the character before matching a specific character in a given string
This is my code:
before :: Char -> [Char] -> Char
before x str = trackelement x ' ' str
trackelement :: Char -> Char -> [Char] -> Char
trackelement x y (z:zs)
| x == z = y
| otherwise = trackelement x z (zs)
My problem is when I try: before 'l' "luis"
The answer is : ' ' (of course, before 'l' there is nothing), and I would like to be '' or Nothing
I tried passing trackelement x '' str instead of trackelement x ' ' str but I have this error Syntax error on ''str
Could you suggest me something?
The answers shown already are good for getting your code to work, but they don't explain why you get the error you're receiving. The reason why that error was shown is that '' is not valid syntax, since there is no such thing as an "empty character". All characters have value, but Strings can be empty. Remember that type String = [Char], and it's very clear that there can be such a thing as an empty list, but characters always have a value. It's comparable to saying you can have an empty list of Ints, namely [], but you can't have an "empty int", whatever that would mean.
You can use a Maybe:
before :: Char -> [Char] -> Maybe Char
before x str = initialise x str
initialise x (y:xs)
| x == y = Nothing
| otherwise = trackelement x y xs
trackelement :: Char -> Char -> [Char] -> Maybe Char
trackelement x y [] = Nothing
trackelement x y (z:zs)
| x == z = Just y
| otherwise = trackelement x z zs
To take care of the corner case before 'l' "luis", we have to add a new initialiser function. It basically checks if the first character matches the searched one. If it does, we return Nothing, because we checked the first character which obviously does not have a preceding one. Else we just call trackelement and use it's result.
As Zeta mentioned, you can combine the functions, which simplifies everything and takes care of the corner case you are currently experiencing.
before _ [x] = Nothing
before a (x:y:xs)
| a == y = Just x
| otherwise = before a (y:xs)
Just using this function, you noticed you have problems when encountering a word containing more than one letter which is also searched for (before 'a' "amalia" -> Just 'm'). Currently the best solution I know of is again splitting this up into more than one function, which brings us back to the solution at the top.
Match the first two elements instead just head and tail. That way you don't even need trackelement:
before :: Eq a => a -> [a] -> Maybe a
before x (a:b:rest)
| a == x = Nothing
| b == x = Just a
| otherwise = before x (b:rest)
before _ _ = Nothing

Resources