How to resolve the algorithm Balanced brackets step by step in the Haskell programming language

Published on 7 June 2024 03:52 AM

How to resolve the algorithm Balanced brackets step by step in the Haskell programming language

Table of Contents

Problem Statement

Task:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Balanced brackets step by step in the Haskell programming language

This Haskell code provides two main functions:

  • isMatching: Determines if a string contains balanced brackets.
  • main: Generates random strings containing brackets and checks their balance.

isMatching Function

The isMatching function takes a string as input and returns a Boolean indicating whether the string contains balanced brackets. It uses an automaton-based approach to check for matching brackets.

The function is defined in terms of a fold over a list of characters, where the accumulator is a string representing the state of the automaton. The state is initially empty.

The automaton transitions are defined as follows:

  • When encountering an opening bracket [, the string is updated to include the opening bracket.
  • When encountering a closing bracket ], if the string contains an opening bracket, it is removed from the string, indicating matching brackets.

main Function

The main function generates 10 random strings using a random number generator. Each string contains a varying number of brackets.

For each generated string, the function checks if it contains balanced brackets using the isMatching function. If the string is balanced, it prints "Good", otherwise it prints "Bad" and indicates the position of the first imbalance.

pairs Function

The pairs function generates pairs of indices to be used in swapping elements of a list. It takes three parameters:

  • l: The lower bound of the indices.
  • u: The upper bound of the indices.
  • r: A random number generator.

The function uses the random number generator to generate a random index j between i and u, where i is the current index. It then returns a pair of indices (i, j) and updates the random number generator.

shuffle Function

The shuffle function takes a list and a random number generator as input and returns a random permutation of the list.

It uses a Fisher-Yates shuffle algorithm, which involves generating pairs of indices and swapping the elements at those indices. The function uses the pairs function to generate the pairs of indices.

bracketProblemIndex Function

The bracketProblemIndex function takes a string and returns a Maybe index representing the first unmatched bracket in the string or Nothing if the string is balanced.

It uses the nesting function to calculate the nesting levels of the brackets in the string and then checks if any of the levels are negative, indicating an unmatched opening bracket. If the last level is non-zero, it indicates an unmatched closing bracket.

showProblem Function

The showProblem function takes a string as input and prints it along with a status message indicating whether the string contains balanced brackets or not.

It uses the bracketProblemIndex function to check for balance and prints "Unmatched" if an imbalance is found, otherwise it prints "OK".

Source code in the haskell programming language

isMatching :: String -> Bool
isMatching = null . foldl aut [] 
  where
    aut ('[':s) ']' = s
    -- aut ('{':s) '}' = s -- automaton could be extended
    aut s x = x:s


brackets = filter isMatching 
           $ [1.. ] >>= (`replicateM` "[]{}")


import Control.Monad
import System.Random
import Text.Printf
import VShuffle

-- Return whether a string contains balanced brackets.  Nothing indicates a
-- balanced string, while (Just i) means an imbalance was found at, or just
-- after, the i'th bracket.  We assume the string contains only brackets.
isBalanced :: String -> Maybe Int
isBalanced = bal (-1) 0
  where
    bal :: Int -> Int -> String -> Maybe Int
    bal _ 0 [] = Nothing
    bal i _ [] = Just i
    bal i (-1) _ = Just i
    bal i n ('[':bs) = bal (i + 1) (n + 1) bs
    bal i n (']':bs) = bal (i + 1) (n - 1) bs

-- Print a string, indicating whether it contains balanced brackets.  If not,
-- indicate the bracket at which the imbalance was found.
check :: String -> IO ()
check s = maybe (good s) (bad s) (isBalanced s)
  where
    good = printf "Good \"%s\"\n"
    bad s n = printf "Bad  \"%s\"\n%*s^\n" s (n + 6) " "

main :: IO ()
main = do
  let bs = cycle "[]"
  rs <- replicateM 10 newStdGen
  zipWithM_ (\n r -> check $ shuffle (take n bs) r) [0,2 ..] rs


module VShuffle
  ( shuffle
  ) where

import Data.List (mapAccumL)
import System.Random
import Control.Monad.ST
import qualified Data.Vector as V
import qualified Data.Vector.Generic.Mutable as M

-- Generate a list of array index pairs, each corresponding to a swap.
pairs
  :: (Enum a, Random a, RandomGen g)
  => a -> a -> g -> [(a, a)]
pairs l u r = snd $ mapAccumL step r [l .. pred u]
  where
    step r i =
      let (j, r') = randomR (i, u) r
      in (r', (i, j))

-- Return a random permutation of the list.  We use the algorithm described in
-- http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm.
shuffle
  :: (RandomGen g)
  => [a] -> g -> [a]
shuffle xs r =
  V.toList . runST $
  do v <- V.unsafeThaw $ V.fromList xs
     mapM_ (uncurry $ M.swap v) $ pairs 0 (M.length v - 1) r
     V.unsafeFreeze v


import Control.Applicative ((<|>))
import Data.List (findIndex, replicate, scanl)
import Data.List.Split (chunksOf)
import System.Random

-------------------- BALANCED BRACKETS -------------------

nesting :: String -> [Int]
nesting = tail . scanl (flip level) 0
  where
    level '[' = succ
    level ']' = pred
    level  _  = id
    

bracketProblemIndex :: String -> Maybe Int
bracketProblemIndex s =
  findIndex (< 0) depths <|> unClosed
  where
    depths = nesting s
    unClosed
      | 0 /= last depths = Just $ pred (length s)
      | otherwise = Nothing


--------------------------- TEST -------------------------
main :: IO ()
main = do
  let g = mkStdGen 137
  mapM_ (putStrLn . showProblem) $
    chunksOf
      6
      (bracket <$> take 60 (randomRs (0, 1) g))

showProblem s =
  case bracketProblemIndex s of
    Just i -> s <> ": Unmatched\n" <> replicate i ' ' <> "^"
    _ -> s <> ": OK\n"

bracket :: Int -> Char
bracket 0 = '['
bracket _ = ']'


  

You may also check:How to resolve the algorithm Sorting algorithms/Cocktail sort step by step in the NetRexx programming language
You may also check:How to resolve the algorithm Doubly-linked list/Element definition step by step in the Pascal programming language
You may also check:How to resolve the algorithm Modified random distribution step by step in the Mathematica/Wolfram Language programming language
You may also check:How to resolve the algorithm String length step by step in the Perl programming language
You may also check:How to resolve the algorithm Euler's sum of powers conjecture step by step in the Kotlin programming language