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
Related
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
please pardon for very beginner level quesion.
I am now trying to introduce Maybe into my previous helper function (which swaps the first two elements of the list) to enable empty list error handling:
...haskell
-- | the helper funtion to only swap the first two elements.
swap_first_two_elements :: [a] -> Maybe [a]
swap_first_two_elements list = case list of
x:y:xs -> Just (y:x:xs)
_ -> Nothing
and invoking it in
interprete s x
| x `elem` ["+","-","*","/","^"] = operate x s
| x `elem` ["inc","dec","sqrt","sin","cos","inv"] = operate2 x s
| x `elem` ["+all"] = [sum s]
| x `elem` ["dup"] = (head s) :s
| x `elem` ["pop"] = tail s
| x `elem` ["swap"] = swap_first_two_elements s
| x `elem` ["clear"] = drop (length s) s
| x `elem` ["*all"] = [product s]
| otherwise = read x:s
where
operate op (x:y:s) = case op of
"+" -> x + y:s
"-" -> y - x:s
"*" -> x * y:s
"/" -> y / x:s
"^" -> y ** x:s
But I am getting an error like
Couldn't match expected type [a] with actual type Maybe[a]
I read other related posts and modified it like:
| x `elem` ["swap"] = swap_first_two_elements Just(s)
Still got error. Could experts offer where I go wrong? Thank you.
So you have
interprete s x
| x `elem` ["pop"] = tail s
| x `elem` ["swap"] = swap_first_two_elements s
Now,
tail :: [a] -> [a]
but
swap_first_two_elements :: [a] -> Maybe [a]
and of course those are two different types altogether.
You can't return a value of one type in some case, and of another type altogether in some other cases. All cases in a function definition must return values of the same type.
A function goes from a type to a type, not to types.
You can fix your definition by wrapping all the other cases' values in a Just, like so:
| x `elem` ["pop"] = Just (tail s)
Just for your code to have more sense, I think you need to spread the Maybe all over the sub-functions, for example in operate, and pop and all other "unsafe" functions, you can take advantage of Maybe type, like divide by 0:
interprete s x
| x `elem` ["+","-","*","/","^"] = operate x s
| x `elem` ["inc","dec","sqrt","sin","cos","inv"] = Just (operate2 x s)
| x `elem` ["+all"] = Just([sum s])
| x `elem` ["dup"] = dup s
| x `elem` ["pop"] = pop s
| x `elem` ["swap"] = swap_first_two_elements s
| x `elem` ["clear"] = Just []
| x `elem` ["*all"] = Just([product s])
| otherwise = Just(read x:s)
pop [] = Nothing
pop (x:xs) = Just xs
dup [] = Nothing
dup s#(x:xs) = Just (x:s)
operate op (x:y:s) = case op of
"+" -> Just(x + y:s)
"-" -> Just(y - x:s)
"*" -> Just( x * y:s)
"/" -> case x of
0 -> Nothing
n -> Just(y / x:s)
"^" -> Just(y ** x:s)
operate _ _ = Nothing
swap_first_two_elements :: [a] -> Maybe [a]
swap_first_two_elements (x:y:xs) = Just (y:x:xs)
swap_first_two_elements _ = Nothing
operate2 = undefined
I don't know what operate2 does, so, I leave it to you. But by sure, it has type [a] -> Maybe [a], so please, make it return a Maybe [a], please.
I am learning Haskell, and I encounter a tricky problem which is evaluating String containing a simple arithmetic expression like (+) and (-) to int.
Take some for example:
"1+2+3" -> 6 , " " -> 0 .
I am trying to type the code. However, I cannot complete that. The following is my code.
evalExpr xs = foldl f 0 xs where
f acc x | x == "+" = (+) acc
| x == "-" = (-) acc
| x == " " = 0
| otherwise = read x ::Int
* In the expression: read x :: Int
In an equation for `f':
f acc x
| x == "+" = (+) acc
| x == "-" = (-) acc
| x == " " = 0
| otherwise = read x :: Int
In an equation for `evalExpr':
evalExpr xs
= foldl f 0 xs
where
f acc x
| x == "+" = (+) acc
| x == "-" = (-) acc
| x == " " = 0
| otherwise = read x :: Int
* Relevant bindings include
acc :: a1 (bound at A2.hs:24:8)
f :: a1 -> [Char] -> a1 -> a1 (bound at A2.hs:24:6)
Could someone help me? Thank you!
Your issue is that the result type of f is different in different branches, which is not allowed. In the first two it is (e.g.) Int -> Int, the type of (+) 3 (which is the same as \x -> 3 + x. The type of the third and fourth lines is just Int. These types are not the same.
Here is a simple solution.
data Token = Plus | Minus | Num Int
lex [] = Nothing
lex ('+':s) = Just (Plus,s)
lex ('-':s) = Just (Minus,s)
lex (num:s) | isDigit num = Just (Num k,rest) where
numstr a (d:s) | isDigit d = numstr (digitVal d:a) s
numstr a r = a,r
digits,rest = numstr [digitVal num] s
k = foldr 0 (\acc d -> acc*10 + d) digits
parse s = case lex s of
Nothing -> []
Just (x,s') -> x:parse s'
eval (Num n:r) = eval (Plus:Num n:r)
eval = eval' 0 where
eval' acc (Plus:Num n:r) = eval' (acc+n) r
eval' acc (Minus:Num n:r) = eval' (acc-n) r
i'm making a function that takes three string values w1, w2 and s, and returns s but with all occurrences of the string w1 replaced by w2.
i have finished it, but there is an error. if w1 is only in the string s once, it works fine. but if it occurs multiple times, it doesn't work. eg:
Main> swapwords "turtles" "goats" "more turtles are becoming blind"
"more goats are becoming blind"
swapwords "turtles" "goats" "the blue turtles, dislike the green turtles"
"the blue turtles, dislike the green goats"
here is the current code:
split :: String -> Char -> String -> [String]
split "" _ "" = []
split "" _ r = [r]
split (x:xs) c ""
| x == c = [[c]] ++ split xs c ""
| otherwise = split xs c [x]
split (x:xs) c r
| x == c = r : [[c]] ++ split xs c ""
| otherwise = split xs c (r ++ [x])
swap :: String -> String -> [String] -> [String]
swap a b [] = []
swap a b (x:xs)
|x==a = [b] ++ xs
|x/=a = [x] ++ swap a b (xs)
join :: [String] -> String
join [] = ""
join (x:xs) = x ++ join (xs)
swapwords :: String -> String -> String -> String
swapwords a b "" = []
swapwords a b c = join (swap a b d)
where d = split c ' ' []
if anybody knows the solution it would help me loads. thanks
Your error is here:
swap :: String -> String -> [String] -> [String]
swap a b [] = []
swap a b (x:xs)
|x==a = [b] ++ xs -- <<< here
|x/=a = [x] ++ swap a b (xs)
When you find the word ayou are replacing it with b, but then you want to continue swapping on the remainder of the list.
I want to create a function in haskell, that returns the number of times a single word is a prefix of a list of words. For example: for the word "go" and the list of words ["ace","going", "gone", "golf"], it should return 3. What I have so far is this:
numberOfPrefixes _ [] = error ("Empty list of strings")
numberOfPrefixes [] _ = error ("No word")
numberOfPrefixes (x:xs) (y:ys)
| isPrefixOf (x:xs) y = 1 + numberOfPrefixes(x:xs) ys
| otherwise = 0
But this only works if the first element of the list of words is actually a prefix. If the first element is not a prefix, the whole thing falls apart. Any help making this right?
isPrefixOf :: (Eq a) => [a] -> [a] -> Bool
isPrefixOf [] _ = True
isPrefixOf _ [] = False
isPrefixOf (x:xs) (y:ys) = x == y && isPrefixOf xs ys
Here's how I'd write this
(.:) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
(.:) = (.) . (.) -- A common utility definition
infixr 9 .:
prefixCount :: Eq a => [a] -> [[a]] -> Integer
prefixCount = length .: filter . isPrefixOf
Or writing it pointfully
prefixCount l ls = length $ filter (isPrefixOf l) ls
If you really want to write it recursively
prefixCount l [] = 0
prefixCount x (l:ls) | <is prefix?> = 1 + prefixCount x ls
| otherwise = prefixCount x ls
and just fill in <is prefix?> with a check whether x is a prefix is of l