[Q] How to distinguish function definition scopes? Because compiler is complaining

Hello there! It’s me again, the OCaml noob.

type choice =
| Add_semicolon
| Add_keyword_in
| Add_nothing

Now I know that you can use let f x = ... to define a function but I still get confused whether to add the keyword in at the end of the definition.

Most of the time, if I add in at the end of function definition, the compiler throws an error.

But in some cases if I don’t add in, neither me or the compiler know where to distinguish the scopes. e. g.

let myfunction a b =
  match a with
  | 1 -> true
  | _ -> false

let another_function x = 
(* Skipping... *)

I noticed that in this case, in was not allowed.

But sometimes code like this

let some_fn (x) (y) (z): unit =
  (* function def here *)

let () = some_fn 1 2 3 (* One more thing, do I need a semicolon here? *)

Causes some error like “Unable to find symbol ‘some_fn’” and the compiler asks me to add a rec to the function definition because it thinks I’m trying to call the function itself inside of the definition.

I’m watching CS3110 YouTube tutorials these days, but

  • Michael Ryan Clarkson uses utop in the tutorial series, which means most of the time a definition ends with ;; which (I heard) considered “Bad Coding Style” when comes to source code editing outside utop
  • As a newcomer from C family languages like Python, it takes time to get used to let ... in and seriously, what’s the difference between OCaml function definitions and Python? You always write definitions separately, isn’t it?

The compiler complains too much about me adding in here and there that I had to spend most of my time setting up OCaml LSP instead of learning. Is there some kind of easy-to-remember ‘rule’ or cheatsheet to get me through these?

A few simple guidelines,

  1. If your let definition is top-level, for instance it should be visible from another modules, you don’t need ‘in’
  2. If your definition is not top-level, meaning you write ‘let’ inside another ‘let’, you need to add ‘in’ after every ‘let’, excluding the top-level ones. (Top-level means directly inside a module)
  3. ‘;;’ double semicolon makes sense only in toplevel, because it denoted the end of phrase. Outside of the toplevel it is not required, don’t write it by hand
  • I recommend using autoformatting tool of OCaml code available as VsCode extension ‘ocaml-platform’. There are different guidelines for formatting the code. AFAIR Janestreet’s one inserts ‘;;’ after every toplevel function definition. This is not mandatory, but compilable.
  1. About ‘;’. In OCaml it means that you call a prcedure in Pascal sense. For example, print_int 52. In this case writing print_int 52; is OK. But if you are a beginner I would recommend to write ‘let’ instead of ‘;’, i.e. let () = print_int 52 in ... for your procedure. It would allow you to avoid a few silly mistakes related to last branch of pattern matching.
2 Likes

Thanks! I kind of understand now.

The one thing confused me was compiler told me to add rec because obviously it means compiler could not distinguish different function definition scopes. Why did that happen? Is it related to that function’s return type?

I don’t entirely understand a question. In OCaml let’s are not recursive by default, so when you write let foo = ... foo ... in .... it tries to find definition of foo somewhere before ‘let foo’ or somewhere after 'let foo =`

1 Like

This behaviour is useful if you want to simulate mutability without its drawbacks. You could do for instance :

let f x =
  let x = x * x in
  let x = x + 3 in
  x * 2

And each x is a different value, there is no mutability, so no risk of x getting edited by some other function, but you still have the ease of gradual modification to arrive at your result. You can even use this to change the type :

let f x =
  let x = x * x in
  let x = x + 3 in
  let x = float_of_int x in
  x /. 2

This you would not be able to replicate with mutability, even in a language like java in which mutability is more used.

1 Like