Identifying repeating consecutive digits on the end of a String in haskell - haskell

So I write a function with the definition
getLastDigits :: String -> String
which finds repeating digits on the end of a String
So, for example.
getLastDigits "1000" should give "000"
getLastDigits "19990299" should give "99"
Coming from a java background I'm not quite sure how to structure this program. I'm thinking of using foldr but I'm fairly sure I can't stop the fold half way when the repeating digits end.
-edit solved. Use the group function.

Okay then, if it is not homework:
lastDigits :: String -> String
lastDigits s = firstDigits . reverse $ s
where firstDigits :: String -> String
firstDigits (x:xs) = x : takeWhile (== x) xs
firstDigits [] = []

import Data.Char (isDigit)
getLastTheSame :: Eq a => (a -> Bool) -> [a] -> [a]
getLastTheSame pred xs = f (reverse xs)
where f (y : ys) | pred y = y : takeWhile (== y) ys
f _ = []
lastDigits :: String -> String
lastDigits = getLastTheSame isDigit
You say you want repeating digits from the end of the string. I presume that if the last character is not a digit then you want the empty string returned.
Recall that type String = [Char].

Related

How can I remove a certain character from a string in Haskell?

I want to make a function that removes a given character from a string.
The prototype is: removeChar :: Char -> String -> String
I tried to do something like this:
removeChar a x = foldr (++) [] (map (\x -> filter f x) x)
where
f x = elem a x
this should be enough, String is nothing but a [Char] so just filter it for that char
removeChar::Char->String->String
removeChar a = filter (/=a)

How do i syntax in haskell

Im trying to write a function that takes in a string and then returns the string as a list of string-words (like the words built-in function) and so far i've written
ord :: String -> [String]
ord [] = []
ord xs = let
ys = groupBy (\x y -> y /= ' ') xs
in filter (not . null) ys
I thougth this would get rid of the empty strings from the list but i only get this output
input:
ord “aa b c - dd”
output:
["aa"," b"," "," "," "," "," "," "," c"," "," "," -"," "," "," "," dd"]
when this is the output i want:
[“aa”, ”b”, ”c”, ”-“, ”dd”]
I get the same result if i try and write
ord :: String -> [String]
ord [] = []
ord xs = filter (not . null) ys
where
ys = groupBy (\x y -> y /= ' ') xs
How do i re-write this code so that i rid the list of its empty strings?
Or use the proper syntax? Im just learning Haskell and im still having trouble with the syntax...
groupBy means that you put x and y in the same group, given the condition is satisfied. But here you group the two together, given y is not equal to a space.
You thus can alter your grouping predicate, and put x and y in the same group, given both are spaces, or non-spaces:
import Data.Char(isSpace)
ord :: String -> [String]
ord [] = []
ord xs = let
ys = groupBy (\x y -> isSpace x == isSpace y) xs
in filter (not . null) ys
or shorter:
import Data.Char(isSpace)
import Data.Function(on)
ord :: String -> [String]
ord [] = []
ord xs = let
ys = groupBy (on (==) isSpace) xs
in filter (not . null) ys
Now we retrieve:
Prelude Data.List> ord "aa b c - dd"
["aa"," ","b"," ","c"," ","-"," ","dd"]
We of course still not obtain the expected result. In stead of filtering out empty strings, we can filter out strings that only contain spacing characters:
import Data.Char(isSpace)
import Data.Function(on)
ord :: String -> [String]
ord [] = []
ord xs = let
ys = groupBy (on (==) isSpace) xs
in filter (not . all isSpace) ys
We do not need to covert the empty case manually, since groupBy on an empty list produces an empty list, we can thus construct a one liner to do the processing:
import Data.Char(isSpace)
import Data.Function(on)
ord :: String -> [String]
ord = filter (not . all isSpace) . groupBy (on (==) isSpace)
Then we obtain the expected result:
Prelude Data.List Data.Char> ord "aa b c - dd"
["aa","b","c","-","dd"]
I wouldn't bother with groupBy at all here. In particular, there's no need to build lists of spaces just to throw them away. Let's start with a function that drops initial spaces and then grabs everything to the first space:
grab :: String -> (String, String)
grab = break isSpace . dropWhile isSpace
Note that the first component of grab xs will be empty if and only if all the elements of xs are spaces.
Now we can write
myWords :: String -> [String]
myWords xs = case grab xs of
([], _) -> []
(beginning, end) -> beginning : myWords end

String manipulation haskell

In the following exercise i want to manipulate a random string input by using functions.
Step 1: I want to remove all characters which are not digits, letters or spaces
Step 2: I want to replace all spaces with '_'
Step 3: I want to convert all numbers to spaces
Step 4: I want to replace all 'a' with 'z' and all 'A' with 'Z'
For lists i already used the filter function and i am wondering if this function can also be used for string inputs. I am not quite sure how to approach this exercise.
Update: I found an approach to solve step 1 and step 3 but i am not quite sure how to put the different functions together in a function which includes every step. Is it possible to call the different functions one after another in the right order in some kind of main function?
import Data.Char
toUpperStr xs = map toUpper xs -- function to convert lower to upper
dropInvalids xs = (filter (\x -> isUpper x || isSpace x || isDigit x)) $
toUpperStr xs
replaceBlank [] = [] -- function to replace " " with "_"
replaceBlank (x:xs) =
if x == ' '
then '_' : replaceBlank xs
else x : replaceBlank xs
Yes, absolutely! That's one of the beautiful things about Haskell.
You can treat Strings as [Char]. In fact, that's what they are!
In GHCi, type :i String - you get type String = [Char].
You can easily compose functions. There's an operator for that, (.).
So (f . g) x is f (g x).
I would improve the code in a few key ways.
Firstly, make the replaceBlank function more general, so it takes a condition and a replacement function.
Secondly, compose all the functions in a "main" function, as you call it.
But do not name the main function main! That name is reserved for the IO action of a program.
It's also important not to think of the final function as "calling" the other functions.
That is imperative terminology, here, we are applying the function(s).
Also, why does your dropInvalids contain a toUpperStr? You never specified the string to be all uppercase in the end.
Also also, be sure to declare the type of your functions.
In this case, the following would be the correct code:
import Data.Char
dropInvalids :: [Char] -> [Char]
dropInvalids = filter (\x -> isLetter x || isSpace x || isDigit x)
-- isLetter exists
replace' :: (a -> Bool) -> (a -> a) -> [a] -> [a]
replace' _ _ [] = []
replace' f g (x:xs) =
if f x
then g x : replace' f g xs
else x : replace' f g xs
-- To replace one value with another, use replace (== a) (const b).
replaceWith :: (a -> Bool) -> a -> [a] -> [a]
replaceWith f b = replace' f (const b)
replace :: Eq a => a -> a -> [a] -> [a]
replace a b = replace' (== a) (const b)
-- The Eq makes sure you can check for equality.
manipulateString :: [Char] -> [Char]
manipulateString = replace 'A' 'Z' . replace 'a' 'z' . replaceWith isDigit ' ' . replace ' ' '_' . dropInvalids

In Haskell how can you multiply a string?

I'm trying to write a function that takes a String and an Int and returns that string "int" times. That is:
duplicate :: String -> Int -> String
If I were to write duplicate "Hello" 3 the output should be "HelloHelloHello".
Easily:
duplicate :: String -> Int -> String
duplicate string n = concat $ replicate n string
The $ is a function of type (a -> b) -> a -> b. The language allows the functions with non-alpha-numeric names to be used in infix form (as operators). I.e., the body of the function above is absolutely identical to the following expression:
($) concat (replicate n string)
What $ does is just allows you to get rid of braces. Meaning that the above expressions are just an alternative to the following expression:
concat (replicate n string)
A String is just a synonym for a list of Char, and the list type is a Monad. Therefore
duplicate :: Int -> String -> String
duplicate n str = [1..n] >>= const str
Or, if you wanted to get all point-free
duplicate = (. const) . (>>=) . enumFromTo 1
Edit
As suggested in the comments
duplicate n str = [1..n] >> str
or
duplicate = (>>) . enumFromTo 1
You can use replicate and concat as follows:
duplicate :: [a] -> Int -> [a]
duplicate = flip $ (concat .) . replicate
-- or as larsmans suggested:
duplicate :: [a] -> Int -> [a]
duplicate = (concat .) . flip replicate
Then use it as duplicate "Hello" 3.
You can use pattern matching.
duplicate _ 0 = []
duplicate xs n = xs ++ duplicate xs (n-1)
or
duplicate xs n | n==0 = []
| otherwise = xs ++ duplicate xs (n-1)
Again a beginners attempt, using recursion
duplicate s n = if n <= 1 then s else duplicate (n-1) s ++ s
though it is a little unclear what the function should do if n is negative or zero. So I chose to return the string itself.

Substitue String in Haskell

Evening,
This is my attempt at an equivalent of "str_replace" in Haskell
strReplace :: (Char, Char) -> String -> String -> String {- Original (y) Parsed (z) -}
strReplace _ "" y = y
strReplace x y z = if (y !! 0) == fst x then strReplace x (drop 1 y) (z:([snd x])) else strReplace x (drop 1 y) (z:(y!!0))
Essentially, the first Tuple is the char to be substitued (Ie ('A', 'B') replaces all As to Bs, the second parameter is the String to be parsed and the third parameter should always be left an empty string. Compiler returns
*** Expression : z : [snd x]
*** Term : z
*** Type : [Char]
*** Does not match : Char
Ideas? :)
The problem with your code is that z : [snd x] is incorrect, z is a list but : wants it to be an element. This can be fixed by using z ++ [snd x].
If seeing the type signatures helps
(:) :: a -> [a] -> [a]
(++) :: [a] -> [a] -> [a]
Or in your specific case
(:) :: Char -> String -> String
(++) :: String -> String -> String
If I may suggest a few improvements to your code however, first strReplace shouldn't force you to pass an empty string
strReplace :: (Char, Char) -> String -> String
Next, we can do this two ways, using higher order functions or explicit recursion.
-- recursion
strReplace _ "" = "" -- Base case
strReplace (a, b) (c:cs) | a == c = b : strReplace (a,b) cs
| otherwise = c : strReplace (a, b) cs
So here if the string is empty we're done, otherwise we pattern match, if the first character is the one to be replaced, we replace it and recurse, otherwise we don't replace it and recurse.
This can actually be done much more cleanly with map though
strReplace (a, b) s = map (\c -> if c == a then b else c) s
This works identically to our previous version, but map abstracts out the looping logic.
z is of type [Char]. You can't use : to cons a [Char] into a [Char] - look at the type signature for :. You would have to use ++ to append one [Char] to another.
Additional points:
It would be better style for strReplace to have a signature :: Char -> Char -> String -> String -> String.
It would be even better style for the signature to be :: a -> a -> [a] -> [a] -> [a]
You shouldn't require the calling code to pass in an empty string. What if they don't - how will they know they made an error? If your recursive call requires it, use an inner function (using let or where).
Where you see a function that looks like foo x y = if (y == ... ) ... else ... it can almost always be improved by either pattern matching or guards.
To expand on point 4, you could rewrite that third line as
strReplace x y z | y !! 0 == fst x = ...
| otherwise = ...
Even better, if you took my advice in point 1 and split the tuple into two simple Char parameters, you could do this:
strReplace x1 x2 y#(y1:ys) z | x1 == y = ...
| otherwise = ...

Resources