Getting Vowels from a String and printing them in Haskell - haskell

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).

Related

How can Haskell code utilise brackets to separate or tidy up information while using list comprehensions?

I am trying to write a function where the expression:
crosswordFind letter inPosition len words
should return all the items from words which
(i) are of the given length len and
(ii) have letter in the position inPosition.
For example, seven-letter words that have ’k’ in position 1, the expression:
crosswordFind ’k’ 1 7 ["funky", "fabulous", "kite", "icky", "ukelele"]
will return
["ukelele"]
Here is what I have so far:
crosswordFind :: Char -> Int -> Int -> [String] -> [String]
crosswordFind letter pos len words =
if isAlpha **words** == letter &&
**words** !! letter == pos &&
length **pos** == len
then words
else []
The code above is after altering to remove the brackets that I placed to separate each condition. The code below is the original one (which is wrong):
crosswordFind :: Char -> Int -> Int -> [String] -> [String]
crosswordFind letter pos len words =
[ if [isAlpha x == letter] &&
[xs !! n == pos] &&
[length x == len]
then words
else [] ]
I understand why it is wrong (because a list of length 1 will be returned), but why can't brackets like these be used to section off code in Haskell?
How can this question be solved using list comprehensions? And I'm wondering what to put in to replace the bolded words as well to make the code run normally.
You can filter with a condition that should satisfy two criteria:
the word has the given length; and
the character on position pos is the given letter.
For a word w of the words we thus check if length w == len and w !! pos == letter.
We thus can implement this with:
crosswordFind :: Eq a => a -> Int -> Int -> [[a]] -> [[a]]
crosswordFind letter pos len words = filter (\w -> length w == len && w !! pos == letter) words
we can also omit the words variable and work with:
crosswordFind :: Eq a => a -> Int -> Int -> [[a]] -> [[a]]
crosswordFind letter pos len = filter (\w -> length w == len && w !! pos == letter)
The above is not very safe: if the pos is greater than or equal to the length, then w !! pos == letter will raise an error. Furthermore for infinite strings (lists of Chars), length will loop forever. I leave it as an exercise to introduce safer variants. You can determine these with recursive functions.
Square brackets are part of list syntax. Nothing else.
Lists.
You can freely utilize round parentheses ( ) for the grouping of expressions.
Some expression types, like let and do, have their own separators {, ;, }, which can also be used, especially to prevent whitespace brittleness.

Haskell - Decode message with pattern

I am new to Haskell and I am currently learning it in school. I got a school task where I have to decode a message that contain certain patterns but I have got no idea how to do this.
The pattern looks something like this: If a letter has a consonant followed by the character 'o' and then once again followed by the same consonant as before it should replace that substring ("XoX" where X is a consonant) with only the consonant. For example if I decode the string "hohejoj" it should return "hej". Sorry if I am explaining this poorly but I think you understand.
This is the code I have so far (but it doesn't work):¨
karpsravor :: String->String
karpsravor s = karpsravor_help s ""
where karpsravor_help s res
|s == "" && (last res) == 'o' = (init res)
|s==""=res
|otherwise = karpsravor_help (drop 3 s) (res ++ (consDecode (take 3 s)))
consDecode :: String->String
consDecode a
|(length a) < 3 = ""
|a == [(head a)]++"o"++[(head a)] = [(head a)]
|otherwise = a
The code is completely broken and poorly written (dumb method) but I have no other idea for how to solve this. Please help!
Pattern match to find occurrences of 'o'. I.e., use
karpsravorhelp (a:'o':b:rest) res = ...
You can't have a:'o':a:rest in the above, you can't pattern match for equality; you'll need to use a guard to make sure that a == b:
karpsravorhelp (a:'o':b:rest) res
| a == b = ...
| otherwise = ...
You'll also have to make sure a and b are consonants, which will just be an 'and' condition for the first guard. For the otherwise condition, make sure that the recursive call calls (b:rest) since you could have something like a:'o':b:'o':b:....
Also make sure to match for two other patterns:
Empty List, []
x:rest, which must go after the above pattern; this way, it will first attempt to match on the a:'o':b:rest pattern, and if that's not there, just take the next letter.
One way to do it would be with unfoldr from Data.List. You can use a case expression to pattern match on a : 'o' : b : rest, and then check that a and b are equal and not vowels using a guard |. Then just include the base cases for when the pattern doesn't match.
notVowel :: Char -> Bool
notVowel = (`notElem` "aeiouAEIOU")
karpsravor :: String -> String
karpsravor = unfoldr $ \str -> case str of
a : 'o' : b : rest
| a == b && notVowel a -> Just (a, rest)
a : rest -> Just (a, rest)
"" -> Nothing

Haskell passing empty Character to a function

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

Detecting Pig-Latin In Haskell

I've tried to write a function to do this but can't get GHCI to understand my code. I'm coming from an OOP background so functional programming is completely new territory for me.
checkPigLatin :: String -> String
checkPigLatin sentence (x:xs)
| check == "true" = "This is Pig Latin"
| otherwise = "Not Pig Latin"
where check = if (x `elem` "aeiouAEIOU", '-' `elem` xs, snd(break('a'==) xs) == 'a', snd(break('a'==) xs) == 'y') then "true"
Several issues here:
The type of your function is String -> String, so it should only have one argument, while your definition has two arguments, sentence and (x:xs).
Don't use strings like "true" and "false". Use booleans. That's what they're for.
The condition of an if must be a boolean. If you want several conditions to hold, use (&&) or and to combine them.
An if-expression must have both a then and an else. You can think of if x then y else z like the ternary x ? y : z operator in some other languages.
'a' and 'y' have type Char, so you can't compare them against strings with ==. Compare with "a" and "y" instead.
However, there is no point in writing if something then True else False. Instead, just use the boolean expression directly.
checkPigLatin :: String -> String
checkPigLatin (x:xs)
| check = "This is Pig Latin"
| otherwise = "Not Pig Latin"
where check = and [ x `elem` "aeiouAEIOU"
, '-' `elem` xs
, snd (break ('a'==) xs) == "a"
, snd (break ('a'==) xs) == "y"
]
There are a few things wrong with your code, but they're all minor.
When you say checkPigLatin sentence (x:xs), you are saying that your function takes two arguments: sentence, and (x:xs). What you mean to say is just (x:xs).
There's no need to return "true", which is a String, when you can return True :: Bool. Bool is already the type that the expression inside the if returns. This means you don't need the if statement at all.
In the predicate in the parentheses, you use , as the logical AND, but in Haskell it's &&
The result of break is a string, so write "a" for its second argument, not 'a'
Lastly - and this is about pig latin, not Haskell - I'm not sure that failing (snd(break('a'==) xs) == "a") is going to guarantee something is not pig latin
Hope this helps, and welcome!
Edit:
Here's the updated code, if you'd like it:
checkPigLatin :: String -> String
checkPigLatin (x:xs)
| check = "This is Pig Latin"
| otherwise = "Not Pig Latin"
where check = (x `elem` "aeiouAEIOU") &&
('-' `elem` xs) &&
(snd(break('a'==) xs) == "a") &&
(snd(break('a'==) xs) == "y")
Not quite sure what's going on in that string-checks, but maybe this is what you need.
checkPigLatin :: String -> String
checkPigLatin [] = "Empty string"
checkPigLatin (x:xs)
| check = "This is Pig Latin"
| otherwise = "Not Pig Latin"
where check = and [ x `elem` "aeiouAEIOU"
, '-' `elem` xs
, snd ( break ('a' == ) xs ) == "a"
, snd (break ('a' == ) xs) == "y"
]
And
pisya> checkPigLatin "checkPigLatin"
"Not Pig Latin"
it :: String

Haskell: Want a better way of doing: value == x || value == y ||

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

Resources