I need convert this string in Char List - haskell

I'm learning haskell. I'm reading a string from a text file and need to make this string becomes a list of char.
The input file is this:
Individuo A; TACGATCAAAGCT
Individuo B; AATCGCAT
Individuo C; TAAATCCGATCAAAGAGAGGACTTA
I need convert this string
S1 = "AAACCGGTTAAACCCGGGG" in S1 =
["A","A","A","C","C","G","G","T","T","A","A","A","C","C","C","G","G","G","G"]
or S1 =
['A','A','A','C','C','G','G','T','T','A','A','A','C','C','C','G','G','G','G']
but they are separated by ";"
What should I do?
What can I do?
after getting two lists, I send them to this code:
lcsList :: Eq a => [a] -> [a] -> [a]
lcsList [] _ = []
lcsList _ [] = []
lcsList (x:xs) (y:ys) = if x == y
then x : lcsList xs ys
else
let lcs1 = lcsList (x:xs) ys
lcs2 = lcsList xs (y:ys)
in if (length lcs1) > (length lcs2)
then lcs1
else lcs2

A rough and ready way to split out each of those strings is with something like this - which you can try in ghci
let a = "Individuo A; TACGATCAAAGCT"
tail $ dropWhile (/= ' ') $ dropWhile (/= ';') a
which gives you:
"TACGATCAAAGCT"
And since a String is just a list of Char, this is the same as:
['T', 'A', 'C', 'G', ...

If your file consists of several lines, it is quite simple: you just need to skip everything until you find “;”. If your file consists of just one line, you’ll have to look for sequences’ beginnings and endings separately (hint: sequence ends with space). Write a recursive function to do the task, and use functions takeWhile, dropWhile.
A String is already a list of Char (it is even defined like this: type String = [Char]), so you don’t have to do anything else. If you need a list of Strings, where every String consists of just one char, then use map to wrap every char (once again, every String is a list, so you are allowed to use map on these). To wrap a char, there are three alternatives:
Use lambda function: map (\c -> [c]) s
Use operator section: map (:[]) s
Define a new function: wrap x = [x]
Good luck!

Related

Remove inputted char from String recursively in Haskell

I'm writing a recursive function that takes a char as input, and removes the char from a string on output.
Eg: INPUT: abbacysa | OUTPUT: bbcys
I'm a beginner in Haskell so just trying to wrap my head around recursion still with practice.
I start out by creating the function with an empty list
I then select the elements within the list and begin the condition guard.
I looked into using drop but I think maybe there is a better way of doing this?
removeChar [] = []
removeChar (x:xs)
| x `elem` "a" = removeChar drop "a"
You start with base of recursion:
removeChar [] = []
If string is not empty, you have two possible options:
It starts from a then you want to skip. So result is just rest of string without letter 'a'.
removeChar ('a':xs) = removeChar xs
It doesn't, then you want to keep it. So result is letter plus rest of string without letter 'a'.
removeChar (x:xs) = x: removeChar xs
Here is a solution where you put in a string and a char you want to remove from the string.
Recursively:
removeChar :: String -> Char -> String
removeChar [] _ = []
removeChar (x:xs) n = if (x == n) then removeChar xs n
else x : removeChar xs n
First we check that char "x" in string (x:xs) equals char "n", if it does then we remove the character, else we keep on looping through the string.
Input: removeChar "abba baby" 'b'
Output: "aa ay"

Capitalizing first letter of words while removing spaces (Haskell)

I'm just starting out in Haskell and this is like the third thing I'm writing, so, naturally, I'm finding myself a little stumped.
I'm trying to write a bit of code that will take a string, delete the spaces, and capitalize each letter of that string.
For example, if I input "this is a test", I would like to get back something like: "thisIsATest"
import qualified Data.Char as Char
toCaps :: String -> String
toCaps [] = []
toCaps xs = filter(/=' ') xs
toCaps (_:xs) = map Char.toUpper xs
I think the method I'm using is wrong. With my code in this order, I am able to remove all the spaces using the filter function, but nothing becomes capitalize.
When I move the filter bit to the very end of the code, I am able to use the map Char.toUpper bit. When I map that function Char.toUpper, it just capitalizes everything "HISISATEST", for example.
I was trying to make use of an if function to say something similar to
if ' ' then map Char.toUpper xs else Char.toLower xs, but that didn't work out for me. I haven't utilized if in Haskell yet, and I don't think I'm doing it correctly. I also know using "xs" is wrong, but I'm not sure how to fix it.
Can anyone offer any pointers on this particular problem?
I think it might be better if you split the problem into smaller subproblems. First we can make a function that, for a given word will capitalize the first character. For camel case, we thus can implement this as:
import Data.Char(toUpper)
capWord :: String -> String
capWord "" = ""
capWord (c:cs) = toUpper c : cs
We can then use words to obtain the list of words:
toCaps :: String -> String
toCaps = go . words
where go [] = ""
go (w:ws) = concat (w : map capWord ws)
For example:
Prelude Data.Char> toCaps "this is a test"
"thisIsATest"
For Pascal case, we can make use of concatMap instead:
toCaps :: String -> String
toCaps = concatMap capWord . words
Inspired by this answer from Will Ness, here's a way to do it that avoids unnecessary Booleans and comparisons:
import qualified Data.Char as Char
toCaps :: String -> String
toCaps = flip (foldr go (const [])) id
where go ' ' acc _ = acc Char.toUpper
go x acc f = f x:acc id
Or more understandably, but perhaps slightly less efficient:
import qualified Data.Char as Char
toCaps :: String -> String
toCaps = go id
where go _ [] = []
go _ (' ':xs) = go Char.toUpper xs
go f (x :xs) = f x:go id xs
There are a number of ways of doing it, but if I were trying to keep it as close to how you've set up your example, I might do something like:
import Data.Char (toUpper)
toCaps :: String -> String
toCaps [] = [] -- base case
toCaps (' ':c:cs) = toUpper c : toCaps cs -- throws out the space and capitalizes next letter
toCaps (c:cs) = c : toCaps cs -- anything else is left as is
This is just using basic recursion, dealing with a character (element of the list) at a time, but if you wanted to use higher-order functions such as map or filter that work on the entire list, then you would probably want to compose them (the way that Willem suggested is one way) and in that case you could probably do without using recursion at all.
It should be noted that this solution is brittle in the sense that it assumes the input string does not contain leading, trailing, or multiple consecutive spaces.
Inspired by Joseph Sible 's answer, a coroutines solution:
import Data.Char
toCamelCase :: String -> String
toCamelCase [] = []
toCamelCase (' ': xs) = toPascalCase xs
toCamelCase (x : xs) = x : toCamelCase xs
toPascalCase :: String -> String
toPascalCase [] = []
toPascalCase (' ': xs) = toPascalCase xs
toPascalCase (x : xs) = toUpper x : toCamelCase xs
Be careful to not start the input string with a space, or you'll get the first word capitalized as well.

How can split a string with two conditions?

So basically I want to split my string with two conditions , when have a empty space or a diferent letter from the next one.
An example:
if I have this string ,"AAA ADDD DD", I want to split to this, ["AAA","A","DDD","DD"]
So I made this code:
sliceIt :: String -> [String]
sliceIt xs = words xs
But it only splits the inicial string when an empty space exists.
How can I also split when a caracter is next to a diferent one?
Can this problem be solve easier with recursion?
So you want to split by words and then group equal elements in each split. You have the functions for doing so,
import Data.List
sliceIt :: String -> [String]
sliceIt s = concatMap group $ words s
sliceItPointFree = concatMap group . words -- Point free notation. Same but cooler
split :: String -> [String]
split [] = []
split (' ':xs) = split xs
split (x:xs) = (takeWhile (== x) (x:xs)) : (split $ dropWhile (== x) (x:xs))
So this is a recursive definition where there are 2 cases:
If head is a space then ignore it.
Otherwise, take as many of the same characters as you can, then call the function on the remaining part of the string.

if-statement with elem results in wrong output

I have written a program whose purpose is to replace/extend every consonant characters in a given word with the constonant itself, an 'o' and the constonant following. If the character is a vocal, the program should ignore it and move on.
For example, the string "progp" should result in "poprorogogpop".The only vocal in the string "progp" is the 'o' and it should therefore not be repeated.
This basically means that I want to construct a program which replaces a char with a String.
This is what I have so far:
rovarsprak :: String -> String --Definition of our function which recieves an String as input and returns a String--
isVocal :: Char -> String --Function which determines if a letter is a vocal or not--
vocals = ["aeiouy"]; --List with relevant vocals--
rovarsprak [] = []; --Case for empty input--
rovarsprak (x:xs) = isVocal(x) ++ rovarsprak(xs)
isVocal x = if elem [x] vocals
then [x]
else [x] ++ "o" ++ [x]
If I compile and run this with the input parameter "progp" I recieve:
"poprorooogogpop"
Everything in the output is correct up until the 'o' character in the middle of the sentence in "progp" since the vocal 'o' should not be repeated in that way.
My suspicion is that error lies within the elem-part of the if-statement or that it may be related with the recursion.
A word of notice, I am extremly new to haskell programming and have searched for issues related with the elem-statement but to no success.
vocals is intended to be a String, not a [String]:
vocals = "aeiouy" --List ['a','e','i','o','u','y'] with relevant vocals--
isVocal would be a good name if it returned a Bool; you are actually returning a possibly different string, so something like consonantToSyllable would be better.
Notice that it's simpler to just return the correct list of letters rather than building a bunch of short lists and concatenating them.
consonantToSyllable x = if elem x vocals then [x] else [x,'o',x]
or
consonantToSyllable x | elem x vocals = [x]
| otherwise = [x,'o',x]
rovarsprak [] = []
rovarsprak (x:xs) = consonantToSyllable x ++ rovarsprak xs
The above recursion is the pattern captured by concatMap: map a function over a list, then concatenate the resulting lists into one list.
rovarsprak word = concatMap consonantToSyllable word
or just
rovarsprak = concatMap consonantToSyllable
You have 2 errors in your code. First, a String is already a list of characters so vocals = "aeiouy" is enough.
Then you can test elem x vocals.
Besides, your looping function rovarsprak is not tail recursive. foldl will make it so, by handling an accumulator in the signature (and it's also clearer that it's a loop) :
rovarsprakBis :: String -> String
rovarsprakBis = foldl (\acc x -> acc ++ isVocal x) ""

Haskell: Pattern Matching to combine String

I'm trying to write a function which adds single characters from a string to a list of strings, for instance
combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]
I've tried this:
combine :: String -> [String] -> [String]
combine (y:ys) (x:xs) =
[x:y, combine ys xs]
A simple one would be
combine :: [Char] -> [String] -> [String]
combine [] _ = []
combine _ [] = []
combine (c:cs) (x:xs) = x ++ [c] : combine cs xs
Or even more simply using zipWith
combine :: [Char] -> [String] -> [String]
combine = zipWith (\c x -> x ++ [c])
I had to do a bit extra to get this to work. I'll break it down for you.
First, I specified the type of the function as [Char] -> [String] -> [String]. I could have used String for the first argument, but what you're operating on conceptually is a list of characters and a list of strings, not a string and a list of strings.
Next, I had to specify the edge cases for this function. What happens when either argument is the empty list []? The easy answer is to just end the computation then, so we can write
combine [] _ = []
combine _ [] = []
Here the _ is matching anything, but throwing it away because it isn't used in the return value.
Next, for the actual body of the function We want to take the first character and the first string, then append that character to the end of the string:
combine (c:cs) (x:xs) = x ++ [c]
But this doesn't do anything with cs or xs, the rest of our lists (and won't even compile with the type signature above). We need to keep going, and since we're generating a list, this is normally done with the prepend operator :
combine (c:cs) (x:xs) = x ++ [c] : combine cs xs
However, this is such a common pattern that there is a helper function called zipWith that handles the edge cases for us. It's type signature is
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
It walks down both input lists simultaneously, passing the corresponding elements into the provided function. Since the function we want to apply is \c x -> x ++ [c] (turned into a lambda function), we can drop it in to zipWith as
combine cs xs = zipWith (\c x -> x ++ [c]) cs xs
But Haskell will let us drop arguments when possible, so we can eta reduce this to
combine :: [Char] -> [String] -> [String]
combine = zipWith (\c x -> x ++ [c])
And that's it!
When you want to combine lists element by element, it is usually a zip you are looking at. In this case, you know exactly how you want to combine the elements – that makes it a zipWith.
zipWith takes a "combining function" and then creates a function that combines two lists using said combining function. Let's call your "combining" function append, because it adds a characters to the end of a string. You can define it like this:
append char string = string ++ [char]
Do you see how this works? For example,
append 'e' "nic" = "nice"
or
append '!' "Hello" = "Hello!"
Now that we have that, recall that zipWith takes a "combining function" and then creates a function that combines two lists using that function. So your function is then easily implemented as
combine = zipWith append
and it will do append on each of the elements in order in the lists you supply, like so:
combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]
You are close. There are a couple issues with what you have.
y has type Char, and x has type String which is an alias for [Char]. This means that you can add y to the top of a list with y : x, but you can't add y to the end of a list using the same : operator. Instead, you make y into a list and join the lists.
x ++ [y]
There must also be a base case, or this recursion will continue until it has no elements in either list and crash. In this case, we likely don't have anything we want to add.
combine [] [] = []
Finally, once we create the element y ++ [x] we want to add it to the top of the rest of the items we have computed. So we use : to cons it to our list.
combine :: String -> [String] -> [String]
combine [] [] = []
combine (x : xs) (y : ys) = (y ++ [x]) : (combine xs ys)
One note about this code, if there is ever a point where the number of characters in your string is different from the number of strings in you list, then this will crash. You can handle that case in a number of ways, bheklilr's answer addresses this.
kqr's answer also works perfectly and is probably the best one to use in practice.

Resources