Calling multiple functions - haskell

I've been trying to call other functions into my main function which will return "valid" if the boolean value is True. The problem is that one of my functions returns a false value and since the others are True, am not receiving the expected output.
import Data.Char(isLower)
charact :: String -> Bool
charact = not . any (`elem` "! #$%&'*+-/><=?^`{|}:,``[]];")
repeatedLocal :: [Char] -> Bool
repeatedLocal [] = False
repeatedLocal (x:xs) = if elem x ['.','_'] then elem x xs else repeatedLocal xs
lowerCase :: [Char] -> Bool
lowerCase x = if all isLower x then True else False
num :: String -> Bool
num = any (`elem` "0123456789")
localPart ::[Char] -> String
localPart [] = "E-mail Invalido"
localPart (x:xs) | length (x:xs) <= 24 && charact (x:xs) && lowerCase (x:xs) && num (x:xs) == True = "E-mail Valido"
| repeatedLocal (x:xs) == False = "E-mail Invalido"
| otherwise = localPart xs
The localPart is a function that I will apply on my main, which will validate if the boolean values from each function are True. The charact will validate if the strings have any type of special characters and filter it to not return True if the String has a special character.
For the repeatedLocal it should check if the specific values repeat more than 1 time in a string - This is part of the code where the value instead of returning True, the function return False if the string doesn't have the specific value which is '.' and '_' instead return True if the characters repeat in the string.
the lowerCase is to return True if the String is lowercase and num if there is a number in the string
The expected output should be, if the charact && lowerCase && num are True then the String is valid and if repeatedLocal is True the string is invalid

import Data.Char(isLower)
charact :: String -> Bool
charact = not . any (`elem` "! #$%&'*+-/><=?^`{|}:,``[]];")
repeatedLocal :: [Char] -> Bool
repeatedLocal [] = False
repeatedLocal (x:xs) = if elem x ['.','_'] then elem x xs else repeatedLocal xs
lowerCase :: [Char] -> Bool
lowerCase x = if all isLower (rmNumCh x) then True else False
num :: String -> Bool
num = any (`elem` "0123456789")
rmNumCh :: String -> String
rmNumCh [] = []
rmNumCh (x:xs) = if (x `elem` "0123456789._") then rmNumCh xs
else x:rmNumCh xs
localPart :: String -> String
localPart str
| length str <= 24 && charact str && lowerCase str
&& num str && not (repeatedLocal str) = "E-mail Valido"
| otherwise = "E-mail Invalido"
I think numbers and characters are not recognized as lower case, so I add a function which eliminates nums and specific caracters (rmNumCh) and use this in the 'lowerCase' function.
And I also think you shouldn't use recursion for the 'localPart' function, because all functions returning boolean values check for a whole string.

How is this?
import Data.Char(isLower)
charact :: String -> Bool
charact = not . any (`elem` "! #$%&'*+-/><=?^`{|}:,``[]];")
repeatedLocal :: String -> Bool
repeatedLocal [] = False
repeatedLocal (x:xs) = if elem x ['.','_'] then elem x xs else repeatedLocal xs
lowerCase :: String -> Bool
lowerCase x = all isLower (rmNumCh x)
num :: String -> Bool
num = any (`elem` "0123456789")
rmNumCh :: String -> String
rmNumCh [] = []
rmNumCh (x:xs) = if x `elem` "0123456789._" then rmNumCh xs else x:rmNumCh xs
localPart :: String -> String
localPart str
| foldl (\acc f -> f str && acc) True [(<=24).length,charact,lowerCase,num,not.repeatedLocal] = "E-mail Valido"
| otherwise = "E-mail Invalido"
I use 'foldl' function.

Related

Replace default value with another default value Haskell

I have the following code which works fine
replacePointsWithZeros :: Eq a => a -> a -> [a] -> [a]
replacePointsWithZeros _ _ [] = []
replacePointsWithZeros replacee replacer (x:xs)
| replacee == x = replacer:replacePointsWithZeros replacee replacer xs
| otherwise = x:replacePointsWithZeros replacee replacer xs
but i want to replace the replacee and replacer arguments with default values, so essentially what i want is
replacePointsWithZeros :: Eq a => [a] -> [a]
replacePointsWithZeros [] = []
replacePointsWithZeros (x:xs)
| '.' == x = '0':replacePointsWithZeros xs
| otherwise = x:replacePointsWithZeros xs
However when I try that it complains about the types with a message I dont really understand as I am very new to Haskell. What am I doing wrong and how can i fix it?
Im assuming the issue is in the line
replacePointsWithZeros :: Eq a => [a] -> [a]
and the fact that im using a instead of Char but if I switch a to Char I get an issue with the Eq statement
Since you write '.' == x, this means that x is a Char, and therefore (x:xs) is a list of Chars, so a [Char], or a String.
Furthermore you write '0': and x: as output, hence that means that the output is a list of Chars as well. This thus means that the signature of replacePointsWithZeros is:
replacePointsWithZeros :: String -> String
replacePointsWithZeros [] = []
replacePointsWithZeros (x:xs)
| '.' == x = '0':replacePointsWithZeros xs
| otherwise = x:replacePointsWithZeros xs
You can make the above more lazy by putting the condition in a mapping function:
replacePointsWithZeros :: String -> String
replacePointsWithZeros [] = []
replacePointsWithZeros (x:xs) = f x : replacePointsWithZeros xs
where f '.' = '0'
f x = x
and we can use a map function instead of the explicit recursion:
replacePointsWithZeros :: String -> String
replacePointsWithZeros = map f
where f '.' = '0'
f x = x

Creating a boolean to return true for Strings starting with a char and the proceeding values being either a char a digit or an underscore

I've been trying to create Boolean that returns True for strings consisting of
a letter followed by one or more letters, digits or underscore characters.
I get the following compile error:
"Couldn't match expected type Char -> Bool
with actual type Bool
Possible cause: or is applied to too many arguments "
isIdentifier :: String -> Bool
isIdentifier [] = False
isIdentifier (x:[]) = False
isIdentifier(x:xs)
| isAlpha x && length(filter(or [isAlpha, isDigit, (=='_')]) xs ) == length xs = True
| otherwise = False
This is my code. I know from the error message that I need to somehow apply or to xs but I don't know how to do so without affecting the filter function.
I was wondering if there were better ways of setting up my function.
The type of or is:
Prelude Data.Char> :t or
or :: Foldable t => t Bool -> Bool
It requires some Foldable container of Bool values, such as [Bool], as input.
The input it receives, however, is a list of predicates:
Prelude Data.Char> :t [isAlpha, isDigit, (=='_')]
[isAlpha, isDigit, (=='_')] :: [Char -> Bool]
Notice that this expression has the type [Char -> Bool]. It doesn't fit the or function.
In order to pass an appropriate argument to the filter function, you'll need to find a way to turn [Char -> Bool] into Char -> Bool. Do you need help with that?
After the considering #Mark Seemann guidance I decided to that i needed to create a function isIdChar :: Char -> Bool that tests if a Char fits the criteria of either being a letter , digit or underscore. I then used the function in my filter. That way the function returned Char -> Bool as #Mark Seemann suggested.
isIdChar :: Char -> Bool
isIdChar c = isAlpha c || isDigit c || c == '_'
isIdentifier :: String -> Bool
isIdentifier [] = False
isIdentifier (x:[]) = False
isIdentifier(x:xs)
| isAlpha x && length(filter isIdChar xs ) == length xs = True
| otherwise = False
Initially I used the || infix operator in my solution but I've also provided solution that uses the or function
isIdChar :: Char -> Bool
isIdChar c = or[isAlpha c, isDigit c , (c == '_')]
isIdentifier :: String -> Bool
isIdentifier [] = False
isIdentifier (x:[]) = False
isIdentifier(x:xs)
| isAlpha x && length(filter isIdChar xs ) == length xs = True
| otherwise = False
This is a great place to use the swing function! Just replace your or with swing any:
swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing f c a = f ($ a) c
isIdentifier :: String -> Bool
isIdentifier [] = False
isIdentifier (x:[]) = False
isIdentifier(x:xs)
| isAlpha x && length(filter(swing any [isAlpha, isDigit, (=='_')]) xs ) == length xs = True
| otherwise = False
You can also simplify your function a bit:
swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing f c a = f ($ a) c
isIdentifier :: String -> Bool
isIdentifier (x:xs#(_:_)) = isAlpha x && all (swing any [isAlpha, isDigit, (== '_')]) xs
isIdentifier _ = False

How to check for each char of a string in Haskell

I've got a homework for a function that checks if a username is valid or not. Allowed chars are underscore, letters, and digits. I'm not allowed to use indexing (!!) and Length
My code so far:
isValid' :: Char -> Bool
isValid' x
| x == '_' = True
| x `elem` ['0'..'9'] = True
| x `elem` ['a'..'z'] = True
| x `elem` ['A'..'Z'] = True
| otherwise = False
isValidUsername :: [Char] -> Bool
isValidUsername x
| map isValid' x = True
| otherwise = False
I want to run my isValid function on all chars of the string i put in isValidUsername. For example:
isValidUsername "MyUsername_123" should return True
isValidUsername "not#v#lidusern#me* *2" should return False
I just can't figure out how to run through all the chars of my string.
Well if you want all the elements to satisfy the isValid' function, you can use the all :: (a -> Bool) -> [a] -> Bool function, so you can rewrite your function to:
isValidUsername :: [Char] -> Bool
isValidUsername x = all isValid' x
or even shorter:
isValidUsername :: [Char] -> Bool
isValidUsername = all isValid'
Note that here it means that the empty string "" is a valid username as well, since for an empty string, all characters (there are no characters) are in the alphanumerical range.
Okay, i figured it out:
isValidUsername :: [Char] -> Bool
isValidUsername x
| False `elem` (map isValid x) = False
| otherwise = True

Convert string to ints. Haskell

Because of the fact I am a beginner when it comes to Haskell and generally functional programmer I would like to someone tell me how to improve my solution. The task is convert string to ints. For example:
"sada21321" -> []
"d123 32 4 123.3 32 " -> [32, 4, 32]
"FFFFFFFFFF" -> []
" " -> []
Solution:
import Data.Char
readInts :: String -> [Int]
readInts s = (( map convertStringToInt ) . (filter (\ elem -> (all isDigit elem))) . getSubstrings)s
getSubstrings :: String -> [String]
getSubstrings s = getSubstrings' s [] [] where
getSubstrings' (h:t) curr res
| h == ' ' && (length curr ) > 0 = getSubstrings' t [] ( res ++ [curr])
| h /= ' ' = getSubstrings' t (curr ++ [h]) res
| otherwise = getSubstrings' t curr res
getSubstrings' [] curr res = if (length curr ) > 0 then ( res ++ [curr] ) else res
reverseList :: [a] -> [a]
reverseList [] = []
reverseList (h:t) = (reverseList t) ++ [h]
convertStringToInt :: String -> Int
convertStringToInt s = convertStringToInt' (reverseList s) 1 0
where
convertStringToInt' [] _ res = res
convertStringToInt' (h:t) m res = convertStringToInt' t (m*10) (res + (((ord h) - 48)*m))
You should take a look at the words and read functions.
(because this is an assignment, I'll let you fill in the details)
Use read ("Your string here.") :: Integer and also check for read. You can convert string to mostly any types you want to.

Valid Parenthese in a string (Haskell implementation)

the problem is to check whether parentheses in a string is properly closed or not. For Haskell implementation, so far I have following. It looks quite awkward. I am looking for a more "Haskell-style" or more elegant implementation.
import Data.List
isValidParentheses :: String -> Bool
isValidParentheses = isValidHelper . (filter isParenthese)
getIndex :: (Eq a) => a -> [a] -> Int
getIndex c xs = getOut (elemIndex c xs)
where getOut (Just x) = x
getOut Nothing = -1
isLeftParenthese :: Char -> Bool
isLeftParenthese c = (getIndex c "{[(") /= -1
isRightParenthese :: Char -> Bool
isRightParenthese c = (getIndex c "}])") /= -1
isParenthese :: Char -> Bool
isParenthese c = isLeftParenthese c || isRightParenthese c
isValidHelper :: String -> Bool
isValidHelper xs = helper xs []
where helper (x:xs) [] | isRightParenthese x = False
| otherwise = helper xs [x]
helper [] st = null st
helper (x:xs) (s:ss) | isLeftParenthese x = helper xs (x:s:ss)
| ((getIndex x "}])") /= (getIndex s "{[(")) = False
| otherwise = helper xs ss
Thanks
Loop through the string
Store opening parentheses in stack
Pop matching parentheses out of the stack
Check if stack is empty at the end
isValid = loop []
where
match '(' ')' = True
match '{' '}' = True
match '[' ']' = True
match _ _ = False
loop st [] = null st
loop st (x:xs)
| x `elem` "([{" = loop (x:st) xs
| x `elem` ")]}" = case st of
open : st' | match open x -> loop st' xs
_ -> False -- unmatched close
| otherwise = loop st xs

Resources