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
Related
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")
Is it OK to write the otherwise part this way? The function should lower the uppercase letters and put the space in front. It keeps giving an error.
functionl s
| s==[] = error "empty"
| otherwise = [ if isUpper c then (" " ++ toLower c) else c | c <-read s::[Char] ]
First, Note that the return type of (" "++ toLower c) is a String ([Char]) if it was done properly - but it isn't. I'll show you below.
But before that, note that in this specific list comprehension, you have else c which is a single Char.
Your return types must match.
This might be a suitable replacement: concat [ if (isUpper c) then (" "++[c]) else [c] | c <-s ]
Your list comprehension is almost right as #Arnon has shown, but you could definitely implement this function more easily using recursion:
-- A descriptive name and a type signature help
-- tell other programmers what this function does
camelCaseToWords :: String -> String
camelCaseToWords [] = []
camelCaseToWords (c:cs)
| isUpper c = ' ' : toLower c : camelCaseToWords cs
| otherwise = c : camelCaseToWords cs
Now, this pattern can be abstracted to use a fold, which is Haskell's equivalent of a basic for-loop:
camelCaseToWords cs = foldr replacer [] cs
where
replacer c xs
| isUpper c = ' ' : toLower c : xs
| otherwise = c : xs
Here each step of the iteration is performed by replacer, which takes the current character c, an accumulated value xs and returns a new value to be used in the next iteration. The fold is seeded with an initial value of [], and then performed over the entire string.
Supposing I had the string "HELLO WORLD" is there a way I can call a function that replaces the character 'O' in the string with the character 'X' so that the new string would look like "HELLX WXRLD"?
How about:
let
repl 'o' = 'x'
repl c = c
in map repl "Hello World"
If you need to replace additional characters later, just add clauses to the repl function.
Sorry for picking up this old thread but why not use lambda expressions?
λ> let replaceO = map (\c -> if c=='O' then 'X'; else c)
λ> replaceO "HELLO WORLD"
"HELLX WXRLD"`
Alternative 1 - Using MissingH
First:
import Data.List.Utils (replace)
Then use:
replace "O" "X" "HELLO WORLD"
Alternative 2 - Using Control.Monad
One funny bastard:
import Control.Monad (mfilter)
replace a b = map $ maybe b id . mfilter (/= a) . Just
Example:
λ> replace 'O' 'X' "HELLO WORLD"
"HELLX WXRLD"
Alternative 3 - Using if
Amon's suggestions was probably the finest I believe! No imports and easy to read and understand!
But to be picky - there's no need for semicolon:
replace :: Eq a => a -> a -> [a] -> [a]
replace a b = map $ \c -> if c == a then b else c
If you depend on the text package (like 99.99% of Haskell applications), you can use T.replace:
>>> replace "ofo" "bar" "ofofo"
"barfo"
Here's another possible solution using divide and conquer:
replaceO [] = []
replaceO (x:xs) =
if x == 'O'
then 'X' : replaceO xs
else x : replaceO xs
First, you set the edge condition "replaceO [] = []".
If the list is empty, there is nothing to replace, returning an empty list.
Next, we take the string and divide it into head and tail. in this case 'H':"ELLOWORLD"
If the head is equal to 'O', it will replace it with 'X'. and apply the replaceO function to the rest of the string.
If the head is not equal to 'O', then it will put the head back where it is and apply the replaceO function to the rest of the string.
replace :: Char -> Char -> String -> String
replace _ _ [] = []
replace a b (x : xs)
| x == a = [b] ++ replace a b xs
| otherwise = [x] ++ replace a b xs
I'm new to Haskell and I've tried to make it simpler for others like me.
I guess this could be useful.
main = print $ charRemap "Hello WOrld" ['O','o'] ['X','x']
charRemap :: [Char] -> [Char] -> [Char] -> [Char]
charRemap [] _ _ = []
charRemap (w:word) mapFrom mapTo =
if snd state
then mapTo !! fst state : charRemap word mapFrom mapTo
else w : charRemap word mapFrom mapTo
where
state = hasChar w mapFrom 0
hasChar :: Char -> [Char] -> Int -> (Int,Bool)
hasChar _ [] _ = (0,False)
hasChar c (x:xs) i | c == x = (i,True)
| otherwise = hasChar c xs (i+1)
My questions is if I put in a string containing such as Hello, today is a Nice Day!! How could I get rid of spaces and punctuation and also replacing the uppercase letters with lowercase?
I know how to delete them but not how to replace them.
Also to get rid of the punctuation.
Sorry I don't know how to mess around with strings, only numbers.
testList xs = [if x = [,|.|?|!] then " " | x<-xs]
import Data.Char
If you want convert the punctuation to space and the characters from upper case to lower case:
testList xs = [if x `elem` ",.?!" then ' ' else toLower x | x<-xs]
Example: testList "TeST,LiST!" == "test list "
If you want to delete the punctuation and convert the characters from upper case to lower case:
testList2 xs = [toLower x | x<-xs, not (x `elem` ",.?!")]
Example: testList2 "Te..S,!t LiS?T" == "test list"
If you don't want or can not import Data.Char, this is an implementation of toLower:
toLower' :: Char -> Char
toLower' char
| isNotUppercase = char -- no change required
| otherwise = toEnum (codeChar + diffLowerUpperChar) -- char lowered
where
codeChar = fromEnum char -- each character has a numeric code
code_A = 65
code_Z = 90
code_a = 97
isNotUppercase = codeChar < code_A || codeChar > code_Z
diffLowerUpperChar = code_a - code_A
I've been without writing a code in Haskell for a long time, but the following should remove the invalid characters (replace them by a space) and also convert the characters from Uppercase to Lowercase:
import Data.Char
replace invalid xs = [if elem x invalid then ' ' else toLower x | x <- xs]
Another way of doing the same:
repl invalid [] = []
repl invalid (x:xs) | elem x invalid = ' ' : repl invalid xs
| otherwise = toLower x : repl invalid xs
You can call the replace (or repl) function like this:
replace ",.?!" "Hello, today is a Nice Day!!"
The above code will return:
"hello today is a nice day "
Edit: I'm using the toLower function from Data.Char in Haskell, but if you want to write it by yourself, check here on Stack Overflow. That question has been asked before.
You will find the functions you need in Data.Char:
import Data.Char
process str = [toLower c | c <- str , isAlpha c]
Though personally, I think the function compositional approach is clearer:
process = map toLower . filter isAlpha
To get rid of the punctuation you can use a filter like this one
[x | x<-[1..10], x `mod` 2 == 0]
The "if" you are using won't filter. Putting an if in the "map" part of a list comprehension will only seve to choose between two options but you can't filter them out there.
As for converting things to lowercase, its the same trick as you can already pull off in numbers:
[x*2 | x <- [1..10]]
Here's a version without importing modules, using fromEnum and toEnum to choose which characters to allow:
testList xs =
filter (\x -> elem (fromEnum x) ([97..122] ++ [32] ++ [48..57])) $ map toLower' xs
where toLower' x = if elem (fromEnum x) [65..90]
then toEnum (fromEnum x + 32)::Char
else x
OUTPUT:
*Main> testList "Hello, today is a Nice Day!!"
"hello today is a nice day"
For a module-less replace function, something like this might work:
myReplace toReplace xs = map myReplace' xs where
myReplace' x
| elem (fromEnum x) [65..90] = toEnum (fromEnum x + 32)::Char
| elem x toReplace = ' '
| otherwise = x
OUTPUT:
*Main> myReplace "!," "Hello, today is a Nice Day!! 123"
"hello today is a nice day 123"
Using Applicative Style
A textual quote from book "Learn You a Haskell for Great Good!":
Using the applicative style on lists is often a good replacement for
list comprehensions. In the second chapter, we wanted to see all the
possible products of [2,5,10] and [8,10,11], so we did this:
[ x*y | x <- [2,5,10], y <- [8,10,11]]
We're just drawing from two lists and applying a function between
every combination of elements. This can be done in the applicative
style as well:
(*) <$> [2,5,10] <*> [8,10,11]
This seems clearer to me, because it's easier to see that we're just
calling * between two non-deterministic computations. If we wanted all
possible products of those two lists that are more than 50, we'd just
do:
filter (>50) $ (*) <$> [2,5,10] <*> [8,10,11]
-- [55,80,100,110]
Functors, Applicative Functors and Monoids