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)
Related
I need to create a function to verify if a password is strong. If have more then 8 characters, at least 1 uppercase, 1 lowercase and 1 digit. But my function doesn't work. What could be wrong?
forte :: String -> Bool
forte s = if (length n >= 8) && (isLower s /= 0) && (isUpper s /= 0) && (isDigit s /= 0)
then True
else False
Welcome to stackoverflow. In the future please be specific when you say something "does not work". Copying and pasting the error message is a great start.
For your case there are a few issues.
There is no variable n. I think you mean s as in length s.
The isLower function operates on characters, not strings (lists of characters). You should check the length of the filtered list (length (filter isLower s) /= 0). Same goes for isUpper and isDigit.
Incidentally, the if statement is entirely unneeded. Any time you write if expr then True else False it is the same as just writing expr.
Applying these suggestions we have:
forte s = (length s >= 8) && (length (filter isLower s) /= 0) && (length (filter isUpper s) /= 0) && (length (filter isDigit s) /= 0)
or with a helper function:
forte s = (length s >= 8) && (cnt isLower /= 0) &&
(cnt isUpper /= 0) && (cnt isDigit /= 0)
where cnt p = length (filter p s)
But I would probably write it as (typed but not tested):
forte s = and [ length s >= 8
, cnt isLower /= 0
, cnt isUpper /= 0
, cnt isDigit /= 0]
where cnt p = length (filter p s)
EDIT: Ah, and I don't know why I didn't consider any instead of counting elements. Thanks to #lorenzo
forte s = and [ length s >= 8
, any isLower s
, any isUpper s
, any isDigit s]
Or with all and any, though this requires you to understand the partial application of $ and function composition (.):
forte s = all ($ s) [ (>= 8) . length
, any isLower
, any isUpper
, any isDigit ]
Hi I am new to haskell and I was just wondering whether it was possible to store a value that has already been removed:
This is my code
input :: Integer -> String
input x = checklength $ intolist x
intolist 0 = []
intolist x = intolist (x `div` 10) ++ [x `mod` 10]
checklength x = if length(x) >= 13 && length(x) <= 16 then doubleall
(init(x)) else "Not valid length of credit card number"
doubleall x = finalcheck $ final $ double (reverse (x))
double x = case x of
[] -> []
[x] -> if (x*2 < 10) then [x*2] else [x*2 `div` 10 + x*2 `mod` 10]
x:y:xs -> (if (x*2 < 10) then [x*2] else [x*2 `div` 10 + x*2 `mod` 10]) ++
y:double xs
final x = (sum x) * 9
finalcheck x = if (x `mod` 10 == ...... ) then "True" else "False"
My code basically takes an input as an integer such as 987564736264535. then makes this integer into a list of number such as [9,8,7..5]. Then it checks the length has to between 13 to 16 digits. If not you get an error statement. If the digits are between the required amount it will go into the doubeall function and remove the last number using (init). the number removed is 5 in which it will double the numbers and reverse the list order. It will then sum the numbers together and multiple by 9. The final step that I have done part of is taking the last digit of the number that has already been summed together and multiplied by 9. So lets give and example lets say I get 456 then I use mod 10 to take the last number which is 6. **Now here is where I am having a problem in which I want to check whether this 6 is equal to the same number that was removed originally in the checklength function when I used init. So in the checklength function I removed the number 5 **
Thanks
Once you remove data, you can't access it again. You need a function that preserves the final checkdigit that you're stripping off.
Since order is (mostly) irrelevant, consider:
validate :: Integer -> Bool
validate x = let digits = toDigits x
in if checkLength digits
then doesMatch . splitCheckdigit $ digits
else False
where
toDigits 0 = [0]
toDigits x = go x
where
go 0 = []
go x = let (d, m) = x `divMod` 10
in m : toDigits d
-- reverses order
checkLength x = let l = length x
in 13 <= l && l <= 16
splitCheckdigit (checkdigit:rest) = (checkdigit, rest)
-- remember we reversed in toDigits, so the *first* digit is the checkdigit!
doesMatch (checkdigit, rest) = let total = (*9) . sum . reduce $ rest
shouldBe = total `mod` 10
in checkdigit == shouldBe
where
reduce (x:y:xs) = (sum . toDigits $ x) : y : reduce xs
reduce [x] = [sum . toDigits $ x]
reduce [] = []
-- note how #toDigits# is reused here rather than redefined.
If you prefer Arrows, validate can be written as:
toDigits >>> ((doesMatch <<< splitCheckdigit) &&& checkLength) >>> uncurry (&&)
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
isValid :: Position -> Bool
isValid Position(x _) = x
isValid Position(_ y) = y
| x 'elem' ['a'..'h'] && y 'elem' [1..8] = True
| otherwise = False
I keep getting this error error: Parse error in pattern: x
I am trying to write a function that tells me whether a given poisition is valid or not. Where x is ['a'..'h'] and y is [1..8]
As explained here: Syntax error on 'mod' Haskell
The syntax for using a named function as an infix operator uses backticks (grave accents, U+0060), not apostrophes:
| x `elem` ['a'..'h'] && y `elem` [1..8] = True
------ ------
| otherwise = False
In addition, Position(x _) and Position(_ y) are not valid patterns—you probably intended to use (Position x _) and (Position x y). Note the x, since x is not in scope in the equation you wrote for (Position _ y).
(Position x _) will match all positions, so I suspect you intended:
isValid :: Position -> Bool
isValid (Position x y)
| x `elem` ['a'..'h'] && y `elem` [1..8] = True
| otherwise = False
Or more simply:
isValid :: Position -> Bool
isValid (Position x y) = x `elem` ['a'..'h'] && y `elem` [1..8]
I keep getting this error error: Parse error in pattern: x I am trying to write a function that tells me whether a given position is valid or not. Where x is ['a'..'h'] and y is [1..8].
The other answers already discussed what is wrong: you used a guard in the clause where there is no bounded x:
isValid Position(_ y) = y
and furthermore you use quotes instead of backticks with the elem function:
x 'elem' ['a'..'h']
So a rigorous fix would be:
isValid :: Position -> Bool
isValid (Position x y)
| x `elem` ['a'..'h'] && y `elem` [1..8] = True
| otherwise = False
Since we actually return the result of the guard, we do not need to use guards and can collapse the guards into one expression:
isValid :: Position -> Bool
isValid (Position x y) = x `elem` ['a'..'h'] && y `elem` [1..8]
Nevertheless since we here work with ranges and the second range are integers, we do not have to use elem on a range, we can use:
isValid :: Position -> Bool
isValid (Position x y) = 'a' <= x && x <= 'h' && 1 <= y && y <= 8
For such small ranges, there will probably not be that much impact on performance, but elem works in O(n) worst case, whereas the two bounds checks work in O(1).
In
| x 'elem' ['a'..'h'] && y 'elem' [1..8] = True
x is unbound. It doesn't appear at all in
isValid Position(_ y) = y
in particular. Also, you probably meant to use `elem`, and not 'elem'.
I am trying to write a function that tells me whether a given poisition is valid or not. Where x is ['a'..'h'] and y is [1..8]
You didn't write the definition of Position, but it seems like this would be something like
data Position = Position Int Int
isValid :: Position -> Bool
isValid (Position x y) = x `elem` ['a'..'h'] && y `elem` [1..8]
(which builds for me).
I need to be able to write a function that shows repeated words from a string and return a list of strings in order of its occurrence and ignore non-letters
e.g at hugs prompt
repetitions :: String -> [String]
repetitions > "My bag is is action packed packed."
output> ["is","packed"]
repetitions > "My name name name is Sean ."
output> ["name","name"]
repetitions > "Ade is into into technical drawing drawing ."
output> ["into","drawing"]
To split a string into words, use the words function (in the Prelude).
To eliminate non-word characters, filter with Data.Char.isAlphaNum.
Zip the list together with its tail to get adjacent pairs (x, y).
Fold the list, consing a new list that contains all x where x == y.
Someting like:
repetitions s = map fst . filter (uncurry (==)) . zip l $ tail l
where l = map (filter isAlphaNum) (words s)
I'm not sure that works, but it should give you a rough idea.
I am new to this language so my solution could be a kind of ugly in the eyes of an Haskell veteran, but anyway:
let repetitions x = concat (map tail (filter (\x -> (length x) > 1) (List.group (words (filter (\c -> (c >= 'a' && c <= 'z') || (c>='A' && c <= 'Z') || c==' ') x)))))
This part will remove all non letters and non spaces from a string s:
filter (\c -> (c >= 'a' && c <= 'z') || (c>='A' && c <= 'Z') || c==' ') s
This one will split a string s to words and group the same words to lists returning list of lists:
List.group (words s)
When this part will remove all lists with less than two elements:
filter (\x -> (length x) > 1) s
After what we will concatenate all lists to one removing one element from them though
concat (map tail s)
This might be inelegent, however it is conceptually very simple. I'm assuming that its looking for consecutive duplicate words like the examples.
-- a wrapper that allows you to give the input as a String
repititions :: String -> [String]
repititions s = repititionsLogic (words s)
-- dose the real work
repititionsLogic :: [String] -> [String]
repititionsLogic [] = []
repititionsLogic [a] = []
repititionsLogic (a:as)
| ((==) a (head as)) = a : repititionsLogic as
| otherwise = repititionsLogic as
Building on what Alexander Prokofyev answered:
repetitions x = concat (map tail (filter (\x -> (length x) > 1) (List.group (word (filter (\c -> (c >= 'a' && c <= 'z') || (c>='A' && c <= 'Z') || c==' ') x)))))
Remove unnecessary parenthesis:
repetitions x = concat (map tail (filter (\x -> length x > 1) (List.group (word (filter (\c -> c >= 'a' && c <= 'z' || c>='A' && c <= 'Z' || c==' ') x)))))
Use $ to remove more parenthesis (each $ can replace an opening parenthesis if the ending parenthesis is at the end of the expression):
repetitions x = concat $ map tail $ filter (\x -> length x > 1) $ List.group $ word $ filter (\c -> c >= 'a' && c <= 'z' || c>='A' && c <= 'Z' || c==' ') x
Replace character ranges with functions from Data.Char, merge concat and map:
repetitions x = concatMap tail $ filter (\x -> length x > 1) $ List.group $ word $ filter (\c -> isAlpha c || isSeparator c) x
Use a section and currying in points-free style to simplify (\x -> length x > 1) to ((>1) . length). This combines length with (>1) (a partially applied operator, or section) in a right-to-left pipeline.
repetitions x = concatMap tail $ filter ((>1) . length) $ List.group $ word $ filter (\c -> isAlpha c || isSeparator c) x
Eliminate explicit "x" variable to make overall expression points-free:
repetitions = concatMap tail . filter ((>1) . length) . List.group . word . filter (\c -> isAlpha c || isSeparator c)
Now the entire function, reading from right to left, is a pipeline that filters only alpha or separator characters, splits it into words, breaks it into groups, filters those groups with more than 1 element, and then reduces the remaining groups to the first element of each.