Haskell passing empty Character to a function - string

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

Related

How to parse a string in haskell?

i m not familiar with askell.
i have to do this function parseChar :: Char -> Parser Char
> parseChar 'a' " abcd "
Just ('a', "bcd")
> parseChar 'z' " abcd "
Nothing
i did this function
type Parser r = String -> Maybe (Char, String)
parseChar :: Char -> Parser Char
parseChar x = \xs -> Just(x, xs)
i dont really understand the \ and how can I take all the string except the second.
Thanks!!
i dont really understand the \ and how can I take all the string except the second.
The \ is a lambda expression \xs -> … is a function that maps a variable xs to the … part. Here you can however move the variable to the head of the clause.
You however need to check if the first element of the string is indeed the element you are parsing:
parseChar :: Char -> Parser Char
parseChar _ "" = Nothing
parseChar x (y:ys)
| x == y = Just (y, ys)
| otherwise = Nothing
Here x is thus the char we want to parse, and "" or (y:ys) the string that we are parsing. "" means that the string is empty, in which case we return Nothing. If the string is not empty, we unpack it in the first character (head) y, and the list of remaining characters (tail) ys. In case x == y, we are thus parsing the correct character, and we can return a 2-tuple wrapped in a Just constructor. In case x is not equal to y, the parser should "fail" and return Nothing.
This then yields:
Prelude> parseChar 'a' "abcd"
Just ('a',"bcd")
Prelude> parseChar 'z' "abcd"
Nothing
Prelude> parseChar 'a' ""
Nothing

Is there an empty character in Haskell?

This is my code:
reverseEncode :: Char -> String -> Int -> Char
reverseEncode _ [] _ = ?
reverseEncode c (x:xs) offset
| alphaPos c == (alphaPos x + offset) `mod` 26 = chr (((alphaPos x + offset) + 65) `mod` 26)
| otherwise = reverseEncode c xs offset
It's just a small method used in a virtual Enigma Machine. After writing the function without the second line and testing it, I got this exception:
Non-exhaustive patterns in function reverseEncode
I then realised I didn't tell the function when to stop recursing. This is how that second line of code was born. Obviously, I could just check the length of the string at each step, but it doesn't look as elegant.
Is there anything in Haskell I can put instead of '?' ? If not, is there anything I can define? Or is this something that could be done in a better way?
EDIT: I've actually tried the version with checking the length of the string, and I get the same exception. So how do I make it work?
There is no empty character. You could however use a character like the Nul character [wiki]. For example with:
reverseEncode :: Char -> String -> Int -> Char
reverseEncode _ [] _ = '\00'
reverseEncode c (x:xs) offset
| alphaPos c == sm `mod` 26 = chr ((sm + 65) `mod` 26)
| otherwise = reverseEncode c xs offset
where sm = alphaPos x + offset
But a more Haskellish approach would be to change the return type. For example by using a Maybe Char instead. This is often used for "computations that can fail". So we could do this with:
reverseEncode :: Char -> String -> Int -> Maybe Char
reverseEncode _ [] _ = Nothing
reverseEncode c (x:xs) offset
| alphaPos c == sm `mod` 26 = Just (chr ((sm + 65) `mod` 26))
| otherwise = reverseEncode c xs offset
where sm = alphaPos x + offset
Here the Nothing thus means we reached the end of the list without meeting the condition, and Just x means that the computation resulted in an answer x.

how to replace a letter in string with Haskell

i have to make Haskell function called markDups that processes a string, replacing all repeated occurrences of a character with the underscore, "_", character.
here is my code i did so far.
makeBar :: Char -> [Char] -> [Char]
makeBar c (x:xs) | c == x = '_':makeBar c xs --turn into a "_"
| otherwise = x:makeBar c xs--ignore and move on
when I run this, here is my output with error message
output should be like this
what should I do?
This seems to work:
import Data.Set
main = putStrLn (markDups "hello world" empty)
markDups :: [Char] -> Set Char -> [Char]
markDups [] set = []
markDups (x:rest) set
| member x set = '_':(markDups rest set)
| otherwise = x:(markDups rest (insert x set))

Recursively dropping elements from list in Haskell

Right now I'm working on a problem in Haskell in which I'm trying to check a list for a particular pair of values and return True/False depending on whether they are present in said list. The question goes as follows:
Define a function called after which takes a list of integers and two integers as parameters. after numbers num1 num2 should return true if num1 occurs in the list and num2 occurs after num1. If not it must return false.
My plan is to check the head of the list for num1 and drop it, then recursively go through until I 'hit' it. Then, I'll take the head of the tail and check that against num2 until I hit or reach the end of the list.
I've gotten stuck pretty early, as this is what I have so far:
after :: [Int] -> Int -> Int -> Bool
after x y z
| y /= head x = after (drop 1 x) y z
However when I try to run something such as after [1,4,2,6,5] 4 5 I get a format error. I'm really not sure how to properly word the line such that haskell will understand what I'm telling it to do.
Any help is greatly appreciated! Thanks :)
Edit 1: This is the error in question:
Program error: pattern match failure: after [3,Num_fromInt instNum_v30 4] 3 (Num_fromInt instNum_v30 2)
Try something like this:
after :: [Int] -> Int -> Int -> Bool
after (n:ns) a b | n == a = ns `elem` b
| otherwise = after ns a b
after _ _ _ = False
Basically, the function steps through the list, element by element. If at any point it encounters a (the first number), then it checks to see if b is in the remainder of the list. If it is, it returns True, otherwise it returns False. Also, if it hits the end of the list without ever seeing a, it returns False.
after :: Eq a => [a] -> a -> a -> Bool
after ns a b =
case dropWhile (/= a) ns of
[] -> False
_:xs -> b `elem` xs
http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.List.html#dropWhile
after xs p1 p2 = [p1, p2] `isSubsequenceOf` xs
So how can we define that? Fill in the blanks below!
isSubsequenceOf :: Eq a => [a] -> [a] -> Bool
[] `isSubsequenceOf` _ = ?
(_ : _) `isSubsequenceOf` [] = ?
xss#(x : xs) `isSubsequenceOf` (y:ys)
| x == y = ?
| otherwise = ?
after :: [Int] -> Int -> Int -> Bool
Prelude> let after xs a b = elem b . tail $ dropWhile (/=a) xs
Examples:
Prelude> after [1,2,3,4,3] 88 7
*** Exception: Prelude.tail: empty list
It raises an exception because of tail. It's easy to write tail' such that it won't raise that exception. Otherwise it works pretty well.
Prelude> after [1,2,3,4,3] 2 7
False
Prelude> after [1,2,3,4,3] 2 4
True

How do I replace space characters in a string with "%20"?

I wanted to write a Haskell function that takes a string, and replaces any space characters with the special code %20. For example:
sanitize "http://cs.edu/my homepage/I love spaces.html"
-- "http://cs.edu/my%20homepage/I%20love%20spaces.html"
I am thinking to use the concat function, so I can concatenates a list of lists into a plain list.
The higher-order function you are looking for is
concatMap :: (a -> [b]) -> [a] -> [b]
In your case, choosing a ~ Char, b ~ Char (and observing that String is just a type synonym for [Char]), we get
concatMap :: (Char -> String) -> String -> String
So once you write a function
escape :: Char -> String
escape ' ' = "%20"
escape c = [c]
you can lift that to work over strings by just writing
sanitize :: String -> String
sanitize = concatMap escape
Using a comprehension also works, as follows,
changer :: [Char] -> [Char]
changer xs = [ c | v <- xs , c <- if (v == ' ') then "%20" else [v] ]
changer :: [Char] -> [Char] -> [Char]
changer [] res = res
changer (x:xs) res = changer xs (res ++ (if x == ' ' then "%20" else [x]))
sanitize :: [Char] -> [Char]
sanitize xs = changer xs ""
main = print $ sanitize "http://cs.edu/my homepage/I love spaces.html"
-- "http://cs.edu/my%20homepage/I%20love%20spaces.html"
The purpose of sanitize function is to just invoke changer, which does the actual work. Now, changer recursively calls itself, till the current string is exhausted.
changer xs (res ++ (if x == ' ' then "%20" else [x]))
It takes the first character x and checks if it is equal to " ", if so gives %20, otherwise the actual character itself as a string, which we then concatenate with the accumulated string.
Note: This is may not be the optimal solution.
You can use intercalate function from Data.List module. It does an intersperse with given separator and list, then concats the result.
sanitize = intercalate "%20" . words
or using pattern matching :
sanitize [] = []
sanitize (x:xs) = go x xs
where go ' ' [] = "%20"
go y [] = [y]
go ' ' (x:xs) = '%':'2':'0': go x xs
go y (x:xs) = y: go x xs
Another expression of Shanth's pattern-matching approach:
sanitize = foldr go []
where
go ' ' r = '%':'2':'0':r
go c r = c:r

Resources