xysun
xysun

Reputation: 2015

OCaml: codes wrapped in parentheses

I am following this draw_string_in_box example in Developing Applications with OCaml

The sample code given is as follows:

let draw_string_in_box pos str bcf col = 
 let (w, h) = Graphics.text_size str in
 let ty = bcf.y + (bcf.h-h)/2 in 
 ( match pos with 
       Center -> Graphics.moveto (bcf.x + (bcf.w-w)/2) ty 
     | Right  -> let tx = bcf.x + bcf.w - w - bcf.bw - 1 in 
                 Graphics.moveto tx ty 
     | Left   -> let tx = bcf.x + bcf.bw + 1 in Graphics.moveto tx ty  );
 Graphics.set_color col;
 Graphics.draw_string str;;

If I remove the parentheses around the "match" part, the code won't work (nothing gets printed). Any idea why?

And more generally, when should I put parenthese around code bits like this?

Thanks.

Upvotes: 2

Views: 505

Answers (2)

jrouquie
jrouquie

Reputation: 4405

As explained by Jeffrey, if you remove the parentheses then the Graphics.set_color col; Graphics.draw_string str statements are understood to be part of the | Left -> case.

This answer is more about when to use parentheses in such code excerpts. In a majority of situations, a pattern matching is the last expression of a function, e.g.:

let f x y =
  foo x;
  match y with
  | Bar -> Printf.printf "Found y=Bar!\n%!"; 42
  | Baz -> Printf.printf "Found y=Baz!\n%!"; 43

And in this case you do not need parentheses. Quite often, it is also the first, and thus the only expression of the function:

let hd list = match list with
  | a :: _ -> a
  | [] -> invalid_arg "hd"

But when you want to do things after the matching, you need to tell OCaml where the matching ends. This is where you use parentheses:

let f x y =
  foo x;
  (match y with
  | Bar -> 42
  | Baz -> 43);
  (* do something, both when y is Bar and when it is Baz: *)
  qux x y;

The same applies to try ... with statements:

let find_a_b a b list =
  (try print_int List.assoc a list
   with Not_found -> Printf.printf "Could not find a=%s.\n%!" a);
  (* Now do something whether or not we found a: *)
  (try print_int List.assoc b list
   with Not_found -> Printf.printf "Could not find b=%s.\n%!" b);

Here the first parentheses are mandatory, the seconds are optional, and usually not written.

Upvotes: 3

Jeffrey Scofield
Jeffrey Scofield

Reputation: 66808

One way to look at it is that after the arrow -> of a match statement you can have a sequence of expressions (separated by ;). Without the parentheses, the following expressions look like they're part of the last case of the match.

You can also have a sequence of expressions (separated by ;) after let. With the parentheses, the following expressions look like they're part of the let, which is what you want.

Personally I avoid using ;. That's how I deal with this problem! Otherwise you have to figure the expression sequence goes with the innermost construct that takes a sequence.

Upvotes: 5

Related Questions