ocaml begin/end pattern matching

Viewed 246

Haven't been able to find much online documentation regarding begin/end in ocaml. I have two different pattern matches in the same function (which I want to be independent of each other), but vscode is parsing them to nest the second inside the first. I've tried surrounding the first pattern match in begin/end, but it's giving me syntax errors:

    begin match c.r with (* first pattern match *)
    | [ r1; r2; r3 ] -> 
        let _ = print_endline (String.make 1 r3.top) in end
    match cl with (* second pattern match *)
    | [] -> []

I get a red underline on end that says Syntax error after unclosed begin, expecting expr. I do not understand what this means, since I wrote end to close the begin, so why is the begin unclosed? The code compiles fine without the begin/end (except that it nests the second pattern match inside the first one). Thanks.

2 Answers

In OCaml begin/end is essentially identical to open/close parentheses. Inside you should have a well-formed expression (as in pretty much any programming language).

What you have inside your begin/end is not an expression, since it ends wih in. A let expression looks like let pattern = expr1 in expr2. You are missing the second expression inside the begin/end.

What you should do (I think) is put begin/end around the inner match like this:

match c.r with
| [r1; r2; r3 ] ->
    let _ = print_endline (String.make 1 r3.top) in
    begin
    match c1 with
    | [] -> []
    ...
    end
| ...

(This code doesn't make a lot of sense but I assume it's just an example.)

As another simplification you can change let _ = a in b to a; b if a is of unit type, as it is in your code.

What Jeffrey Scofield said. Consider how this can become confusing when we nest matches. How do we read the following?

match "foo" with
| "bar" -> 42
| "foo" ->      
  match "baz" with
  | "baz" -> 27
  | _ -> 19
| _ -> 33

The indentation makes it fairly clear how this is meant, but OCaml doesn't care about your pretty indentation. It could just as easily be that you meant:

match "foo" with
| "bar" -> 42
| "foo" ->      
  match "baz" with
  | "baz" -> 27
| _ -> 19
| _ -> 33

Or:

match "foo" with
| "bar" -> 42
| "foo" ->      
  match "baz" with
  | "baz" -> 27
  | _ -> 19
  | _ -> 33

Either parentheses or begin/end disambiguate this situation.

match "foo" with
| "bar" -> 42
| "foo" ->      
  (match "baz" with
   | "baz" -> 27
   | _ -> 19)
| _ -> 33

Or:

match "foo" with
| "bar" -> 42
| "foo" ->      
  begin
    match "baz" with
    | "baz" -> 27
    | _ -> 19
  end
| _ -> 33

One more thing...

Nested match expressions are often unnecessary. Consider when you have a nested match if you can't more cleanly express the same as a single level match on a tuple of values.

match a with
| X -> ...
| Y ->
  (match b with
   | Z -> ...
   | W -> ...
   | _ -> ...)
| U ->
  (match c with
   | F -> ...
   | G -> ...
   | _ -> ...)
| _ -> ...

vs.

match a, b, c with
| X, _, _ -> ...
| Y, Z, _ -> ...
| Y, W, _ -> ...
| Y, _, _ -> ...
| U, _, F -> ...
| U, _, G -> ...
| U, _, _ -> ...
| _, _, _ -> ...
Related