I am reading the Algorithm Design Manual Second Edition and this is from an exercise question. Quoting the question
A common problem for comp
C# 7 or so now also has tuples. You don't need the out argument anymore.
As many others pointed out, there is no need for a stack or a queue or alike.
Just a balance counter suffices.
-- Checks the balance of braces in a string.
-- Error case 1: More closes than open. We can identify the first culprit by index.
-- Error case 2: More opens than closes. We return the length of the String,
-- indicating that there are closed braces missing.
-- Good case: As many opens as closes. We return (True,Nothing)
checkBraces :: String -> (Bool,Maybe Int)
checkBraces [] = (True,Nothing)
checkBraces s =
let (balance,offender) = foldl account (0,-1) $ zip [0..] s in
if balance == 0
then (True,Nothing)
else (False,Just $ if -1 == offender then length s else offender)
where
account :: (Int,Int) -> (Int, Char) -> (Int,Int)
account acc@(_,off) _ | off /= -1 = acc -- Once there was an error we stop looking what happens.
account acc@(b,off) (i,'(') = (b+1,off) -- One more open brace.
account (b,off) (i,')') -- One more closed brace.
| b <= 0 = (b-1,i) -- Ouch. We closed more than we opened!
| otherwise = (b-1,off) -- Okay.
account acc (i,_) = acc -- Some other character (Not in ['(',')'])
testCases =
[ ("",True)
, ("(",False)
, (")",False)
, ("))((",False)
, ("()()",True)
, ("(()))",False)
]
test =
all ((==) True) . fmap testOne $ testCases
where
testOne (tc,expected) =
let (actual,_) = checkBraces tc in
actual == expected
Side note: The syntax highlighting for Haskell here needs some improvement, right? :)