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"
Related
This question already has answers here:
Better exception for non-exhaustive patterns in case
(2 answers)
Closed last year.
I want to write a match :: String -> String -> Maybe Char function that should return the first string's different character (e.g. Just 'b'). If both strings are identical or the first string is the second string's prefix, the function should return Nothing.
So far, I have this code:
match :: String -> String -> Maybe Char
match [] [] = Nothing
match [x] [] = Just x
match [] [y] = Nothing
match [x] [y]
| x == y = Nothing
| otherwise = Just x
match (x:xs) (y:ys)
| x == y = match xs ys
| otherwise = Just x
Which returns the correct value for, let's say match "apple" "aple" == Just 'p', but for the case below, I get a Non-exhaustive patterns error, which is strange becuase I thought I've covered every case:
*main> match (replicate 21 'a') (repeat 'a')
*** Exception: match.hs:(64,1)-(72,22): Non-exhaustive patterns in function match
Matching with a singleton list ([x], a list with exactly one element) here is not necessary. You can work with the empty list [] and the "cons" (x:xs):
match :: String -> String -> Maybe Char
match [] _ = Nothing
match (x:_) [] = Just x
match (x:xs) (y:ys)
| x == y = match xs ys
| otherwise = Just x
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) ""
I'm new in Haskell and I'm tring to write a simple function that counts the number of occurences of a substring in a string.
For example : "There is an apple" and I want to count how many times "is" in the sentence, in this case the result should be 1.
This is what I've tried:
countOf :: String -> Int
countOf x = length [n | n <- words x, filter "is" x]
According what I've studied it should work, but it doesn't. I really don't know how to solve the problem, and also don't know what the error message I get means:
input:1:41:
Couldn't match expected type `Bool' with actual type `[a0]'
In the return type of a call of `filter'
In the expression: filter "a" x
In a stmt of a list comprehension: filter "a" x
The function filter has the type
filter :: (a -> Bool) -> [a] -> [a]
This means that its first argument is another function, which takes an element and returns a Bool, and it applies this function to each element of the second argument. You're giving a String as the first argument instead of a function. Maybe you want something more like
countOf x = length [n | n <- words x, filter (\w -> w == "is") x]
But this won't work either! This is because any extra expression in a list comprehension has to be a Bool, not a list. filter returns a list of elements, not a Bool, and this is actually the source of your compiler error, it expects a Bool but it sees a list of type [a0] (it hasn't even gotten far enough to realize it should be [String]).
Instead, you could do
countOf x = length [n | n <- words x, n == "is"]
And this would be equivalent to
countOf x = length (filter (\w -> w == "is") (words x))
Or with $:
countOf x = length $ filter (\w -> w == "is") $ words x
Haskell will actually let us simplify this even further to
countOf x = length $ filter (== "is") $ words x
Which uses what is known as an operator section. You can then make it completely point free as
countOf = length . filter (== "is") . words
I would do like this:
countOf :: String -> Int
countOf x = length [n | n <- words x, compare "is" n == EQ]
Demo in ghci:
ghci> countOf "There is an apple"
1
You can put the comparison straight in the comprehension:
countOf x = length [n | n <- words x, n == "is"]
Actually, you try to count the number of occurences of a word in a string. In case you look for a substring:
import Data.List (inits, tails)
countOf = length . filter (=="is") . conSubsequences
where
conSubsequences = concatMap inits . tails
One could also try a foldr:
countOf :: String -> Int
countOf x = foldr count 0 (words x)
where
count x acc = if x == "is" then acc + 1 else acc
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!
I've seen the other threads about missing split function but I didn't want to peek as I do this for learning purposes and want to figure out myself. So here it is:
split :: Char -> String -> [String]
split c xs | null f = []
| otherwise = f : split c s'
where (f,s) = break (== c) xs
s' | null s = s
| otherwise = tail s
It seems to work fine (please tell me if anything is wrong with it) but when I use a splitting character that is not in the string then the function returns a list with a single element of the original string whereas I want it to return an empty list. I can't figure out how to do it.
Any ideas?.
You can simply write a wrapper function, changing the result of your original one:
split' x xs = go (split x xs) where
go [_] = []
go ys = ys
There are many ways to write a split function, e.g.
split x xs = foldl' go [[]] xs where
go (ys:yss) y | y == x = []:ys:yss
| otherwise = (y:ys):yss
or
import Data.List
split x xs = map tail $ groupBy (const (/=x)) (x:xs)