rjc810
rjc810

Reputation: 495

ocaml begin/end pattern matching

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.

Upvotes: 1

Views: 1752

Answers (2)

Chris
Chris

Reputation: 36620

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 what the programmer 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, _, _ -> ...
| _, _, _ -> ...

Note that the number of outcomes remains eight in either case.

Naturally this doesn't work if the inner match is against a computation on the value which would not otherwise need to occur or could not occur in other cases.

Upvotes: 3

Jeffrey Scofield
Jeffrey Scofield

Reputation: 66823

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 with 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.

Upvotes: 5

Related Questions