I'm new to Haskell, so am sorry if this is incredibly obvious...
I have made the following function (used here as an example to ask about multiple value==something || value==somethingElse checks) to check if a character is a number:
isDigit :: Char -> Bool
isDigit x =
if
x == '0'
|| x == '1'
|| x == '2'
|| x == '3'
|| x == '4'
|| x == '5'
|| x == '6'
|| x == '7'
|| x == '8'
|| x == '9'
then True
else False
Surely though there must be a neat way to write functions like the one above, so you don't have to repeat the || x == quite so much?
Thank you in advance for your help :)
(If it's relevant: I'm using Hugs as the interpreter.)
In this case you can use elem from the Prelude:
isDigit x = elem x "0123456789"
(Remember that strings are lists of Char)
Or you can use isDigit from Data.Char :-)
Yes, there is a neat way to write almost every repetitive pattern. Here's how to derive it for this one. Start with the list of chars (I'll just do 0-4 for brevity)
"01234"
Map the comparisons:
map (x ==) "01234"
= [x == '0', x == '1', x == '2', x == '3', x == '4']
= (x == '0') : (x == '1') : (x == '2') : (x == '3') : (x == '4') : []
Then use foldr. foldr f z is best described as a function that takes a list and replaces : with f and [] with z.
foldr (||) False (map (x ==) "01234")
= x == '0' || x == '1' || x == '2' || x == '3' || x == '4' || False
And there you have it. foldr is kind of the granddaddy of list functions, so this is the "lowest level" way to do it without explicit recursion. Here are two more spellings for your vocabulary:
isDigit x = any (x ==) "0123456789"
isDigit x = or [ x == d | d <- "0123456789" ]
If I had to guess at the most common "idiomatic" spelling, it would probably be this variant of the first one:
isDigit = (`elem` "0123456789")
Once you get familiar with all the handy functions in the Prelude, writing code like this is a joyous breeze :-)
Another style issue that I didn't see mentioned already is that a function
if expr then True else False
is equivalent to simply
expr
Related
Basically i have this code
ola xs = foldl (\acc x -> if (chr x >= 65 && chr x <= 71 || chr x >= 97 && chr x <= 103) then acc (++) x) [] xs
And when i try to load it on ghci it says i have a parse error in the last parenthesys so can you help me? What is wrong here?
You are finding all occurrecne of letters A to G in a string in case in sensitive manner. As said in comments you are missing the else case. The else case should simply be returning the acc variable.
But still there are mistakes in your program. The function chr takes a number and returns ascii character. What you need is ord, which takes char and returns ascii value.
So the version of your program will be
ola xs = foldl (\acc x -> if (ord x >= 65 && ord x <= 71 || ord x >= 97 && ord x <= 103) then acc ++ [x] else acc) [] xs
Char data type is already of the Ord class, so you can compare them. No need for using ord. With this you can write above as
ola xs = foldl (\acc x -> if (x >= 'A' && x <= 'G' || x >= 'a' && x <= 'g') then acc ++ [x] else acc) [] xs
There is special function in list known as filter which takes from a list only the needed elements. Using filter the above program will be.
ola xs = filter (\x -> x >= 'A' && x <= 'G' || x >= 'a' && x <= 'g') xs
now the argument can simply be removed and it can be simply written as
ola = filter (\x -> x >= 'A' && x <= 'G' || x >= 'a' && x <= 'g')
Bonus :-
But now what if you have some random character you want to check. You can first create a string for the characters you want to filter. For the above example this will suffice.
strList=['A'..'G','a'..'g'];
Now filter using elem. elem checks if a given element is present in string.
ola xs = filter (\x -> elem x strList) xs
Bonus 2:-
What if you want to remove the arguments xs. For that first you need to first flip the arguments of the elem, so that the list will be first.
ola = filter ((flip elem) strList)
I am trying to make a program that receives a STRING and returns the percentage of 'C' and 'A' in it. However it is going to me wrong, this is my code:
function' :: [Char] -> Double
function' xs = 100* ( fromIntegral final0 )
where final0 = length $ filter (\x-> x == 'C'|| x == 'G') xs
if I run: function '$ replicate 20' C ', return me 2000.0 and should give me 1.0
Some errors in the question
You said
'C' and 'A'
While your code says
\x-> x == 'C'|| x == 'G'
What you're doing
You're measuring the number of Cs and Gs, and *100, and return the result.
How to solve
do not *100, do / length xs.
Solution
function' xs = fromIntegral final0 / fromIntegral final1
where final0 = length $ filter (\x-> x == 'C'|| x == 'G') xs
final1 = length xs
I've just started learning Haskell and I'm a bit stuck.
https://gyazo.com/b70aee3b5a031a6d65ea2fe993ea0824
I've made an attempt at it and I don't really know how to get my head around where I'm going wrong.
vowels :: String -> String
vowels [] = []
vowels xs = [] == [ x | x <- vowels , x == "a" || x == "e" || x == "i" || x == "o" || x == "u" ]
First of all
you're almost there
vowels xs = [ x | x <- xs , x == 'a' ||
x == 'e' ||
x == 'i' ||
x == 'o' ||
x == 'u' ]
But what is the actual error?
you were using the function as an input to your list
String litterals are surrounded by " where Char litterals have ' and internally Strings in Haskell are just [Char] so you need to use characters.
But haskell is known for conciseness and expressivity - list comprehensions are a nice way but can we do better?
yes we can!
What you actually, do is implement a filter, so let us analyze what you are filtering - vowels, so let us extract that part:
isVowel x = x == 'a' || ... || x == 'u'
well this is still not elegant, but there is a function called elem that checks whether something is contained in a list.
isVowel x = x `elem` ['a','e','i','o','u']
and knowing that String = [Char] we can rewrite that (using so called backtick-syntax which allows to use functions of 2 parameters as an infix function)
isVowel :: Char -> Bool
isVowel x = x `elem` "aeiou"
then coming back to the original problem now that we have a function telling us what a vowel is...
vowel :: String -> String
vowel = filter isVowel
now you might be interested where is the xs - well since haskell has a great type system it can derive that there is one parameter missing on both sides of the = sign, you don't need to write that yourself (this style is called pointfree).
I am writing a very simple function which transforms a string by replacing a certain combinations of characters into another. (e.g. "ab" to "a")
I am a noob in Haskell, and I get error: "Type error in explicitly typed binding"
Could you please tell me what is the problem?
Code:
transform :: String -> String
transform [] = []
transform [x] = x
transform (x:y:xs)
| x == "a" && y == "b" = "a" ++ (transform xs)
| x == "b" && y == "a" = "b" ++ (transform xs)
| x == "b" && y == "b" = "a" ++ (transform xs)
| x == "a" && y == "a" = "aaa" ++ (transform xs)
Thank you!
In the final transform pattern, you are using string literals for "a" and "b" when they should be characters.
transform :: String -> String
transform [] = []
transform [x] = [x]
transform (x:y:xs)
| x == 'a' && y == 'b' = "a" ++ (transform xs)
| x == 'b' && y == 'a' = "b" ++ (transform xs)
| x == 'b' && y == 'b' = "a" ++ (transform xs)
| x == 'a' && y == 'a' = "aaa" ++ (transform xs)
Also, there was a bug in the second transform definition, where you needed to wrap x in brackets because it was returning a list of characters.
(You may also want to have a final pattern match to handle any other input, since you'll get a non-exhaustive error if you run this against a string like "zzz")
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