Checking if a string consists of balanced parenthesis

后端 未结 4 2382
渐次进展
渐次进展 2021-02-20 04:01

I wrote the following program to check strings for balanced parenthesis:

isBalanced xs = isBalanced\' xs []

isBalanced\' [] [] = True
isBalanced\' [] _  = False         


        
相关标签:
4条回答
  • 2021-02-20 04:22

    As Henning said, parser combinators would work for this. Here's an example using Parsec:

    import Text.Parsec
    
    grammar = many braces >> return ()
        where braces = choice [ between (char '(') (char ')') grammar
                              , between (char '[') (char ']') grammar
                              , between (char '{') (char '}') grammar
                              ]
    
    isBalanced :: String -> Bool
    isBalanced input = case parse (grammar >> eof) "" input of
                           Left  _ -> False
                           Right _ -> True
    
    0 讨论(0)
  • 2021-02-20 04:27

    Using a left fold

    import Data.List (foldl')
    
    isBalanced xs = null $ foldl' op [] xs
      where
        op ('(':xs) ')' = xs
        op ('[':xs) ']' = xs
        op ('{':xs) '}' = xs
        op xs x = x:xs
    

    The fold builds up a stack of previously encountered characters, stripping away any matches as it finds them. If you end up with an empty list, the string is balanced.

    Using a left fold in the Maybe monad

    The disadvantage of using a left fold is that the entire string must always be scanned through. It would be nice to abort the operation with a failure should a closing brace be found without a matching opening brace. Here's a version that does just that.

    import Control.Monad (foldM)
    
    isBalanced' xs = maybe False null $ foldM op [] xs
      where
        op ('(':xs) ')'          = Just xs
        op ('[':xs) ']'          = Just xs
        op ('{':xs) '}'          = Just xs
        op xs x | x `elem` ")]}" = Nothing
                | otherwise      = Just (x:xs)
    
    0 讨论(0)
  • 2021-02-20 04:37

    Probably overkill for a problem this simple, but you could try looking up parser combinators.

    As a more elementary simplification, you could rewrite your recursion into folding over a function that takes a stack and a character from the string to a new stack. (Whether this would make actually it simpler is in the eye of the beholder, though).

    0 讨论(0)
  • 2021-02-20 04:39

    I think hammar's answer is the best, but here are smaller steps you can do - use null and lookup:

    {-# LANGUAGE PatternGuards #-}
    isBalanced xs = isBalanced' xs []
    
    isBalanced' [] x = null x
    
    isBalanced' (c:xs) ys | Just d <- lookup c par = isBalanced' xs (d:ys)
      where par = [('(',')'), ('[',']'),('{','}')]
    
    isBalanced' _  [] = False
    
    isBalanced' (x:xs) (y:ys) = x == y && isBalanced' xs ysl
    

    Your example positives and negatives data should definitely use map, or even all.

    0 讨论(0)
提交回复
热议问题