11

我编写了以下程序来检查字符串是否平衡括号:

isBalanced xs = isBalanced' xs []

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

isBalanced' ('(':xs) ys = isBalanced' xs (')':ys)
isBalanced' ('[':xs) ys = isBalanced' xs (']':ys)
isBalanced' ('{':xs) ys = isBalanced' xs ('}':ys)

isBalanced' _  [] = False

isBalanced' (x:xs) (y:ys) = (x == y) && (isBalanced' xs ys)

以下是一些示例数据:

positives = [
    isBalanced "",
    isBalanced "()",
    isBalanced "[]",
    isBalanced "{}",
    isBalanced "([]){}[{}]"
    ]

negatives = [
    isBalanced "(",
    isBalanced "[",
    isBalanced "{",
    isBalanced ")",
    isBalanced "]",
    isBalanced "}",
    isBalanced "([)]",
    isBalanced "{]",
    isBalanced ")("
    ]

由于这个程序只使用了最基本的显式递归构建块,我想知道是否有一种更短、更高级的方法涉及我还不知道的语言设施。


好的,我从几个答案和评论(以及我自己的想法)中提炼出以下解决方案:

import Text.Parsec

grammar = many parens >> return () where
 parens = choice [ between (char opening) (char closing) grammar
                 | [opening, closing] <- ["()", "[]", "{}"]]

isBalanced = isRight . parse (grammar >> eof) ""

isRight (Right _) = True
isRight _         = False
4

4 回答 4

18

正如Henning 所说,解析器组合器将为此工作。这是一个使用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
于 2011-08-26T19:30:02.697 回答
10

使用左折叠

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

折叠会建立一堆以前遇到的字符,并在找到匹配项时将其删除。如果最终得到一个空列表,则字符串是平衡的。

在 Maybe monad 中使用左折叠

使用左折叠的缺点是必须始终扫描整个字符串。如果在没有匹配的左大括号的情况下找到右大括号,那么以失败中止操作会很好。这是一个可以做到这一点的版本。

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)
于 2011-08-26T20:06:17.287 回答
3

我认为 hammar 的答案是最好的,但您可以执行以下小步骤 - 使用nulllookup

{-# 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

您的示例positivesnegatives数据绝对应该使用map,甚至all

于 2011-08-26T19:41:30.777 回答
2

对于这么简单的问题可能有点矫枉过正,但您可以尝试查找parser combinators

作为更基本的简化,您可以将递归重写为折叠一个函数,该函数从字符串中获取一个堆栈和一个字符到一个新堆栈。(虽然这是否会使它变得更简单,但在旁观者看来)。

于 2011-08-26T18:58:41.373 回答