Check Matching Brackets in OCaml Example

In OCaml, implement a tail-recursive function check_brackets : string -> bool such that check_brackets s is true if and only if the brackets (), {} and [] are paired up properly in s.


Solution

To solve this problem, we need to traverse the input string and check whether each opening and closing bracket is valid. When an opening bracket (, { or [ is encountered, it must be closed by ), } and ] respectively. That is, whenever a closing bracket is encountered, it must have been preceeded by the corresponding opening bracket.

The string traversal is handled using an index i ranging from 0 to String.length s. A stack of characters is leveraged to keep track of the opening brackets encountered, in first in, first out order. When a closing bracket is encountered, this stack can be peeked at to check if the latest opening bracket is indeed the correct one. Once the input string is fully traversed, we need to ensure that there are no leftover opening brackets in the stack.

ocaml
let check_brackets : string -> bool =
  let rec aux : string -> int -> int -> char list -> bool =
    fun s i n bs ->
      if i < n then
        match bs, s.[i] with
        | _, ('(' as b)
        | _, ('{' as b)
        | _, ('[' as b) ->
          (* Encountered a new opening bracket *)
          aux s (i + 1) n (b :: bs)
        | '(' :: bs', ')'
        | '{' :: bs', '}'
        | '[' :: bs', ']' ->
          (* Encountered a valid closing bracket *)
          aux s (i + 1) n bs'
        | _, ')'
        | _, '}'
        | _, ']' ->
          (* Encountered an invalid closing bracket *)
          false
        | _ ->
          (* Fallback to continuing the string traversal *)
          aux s (i + 1) n bs
      else
        match bs with
        | [] ->
          (* There are no leftover opening brackets *)
          true
        | _ :: _ ->
          (* There are leftover opening brackets *)
          false
  in
  fun s -> aux s 0 (String.length s) []