rnso
rnso

Reputation: 24535

Need and purpose of `()` and `in` in ocaml code

I am trying to understand Ocaml and running following code from here:

let rec fib n =  
  if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main () =
  let arg = int_of_string Sys.argv.(1) in
  print_int (fib arg);
  print_newline ();
  exit 0;;
main ();;

However, I cannot understand why () and in are needed and why following code (which is much cleaner) does not work:

let rec fib n =
  if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main =
  let arg = int_of_string Sys.argv.(1);
  print_int (fib arg);
  print_newline;
  exit 0;;  (* Line 7. Error is coming from here.*)
main;;

Above code gives following error:

File "fib_simpler.ml", line 7, characters 8-10:
Error: Syntax error

I notice that removing () only give warning, while removing in gives error and program execution stops.

Keeping in and () after print_newline removes all warnings and errors. So () is not really needed with main keywords.

Above is shown in comments below:

let rec fib n =  (*(n) also works here*)
  if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main () =  (*removing () here does not matter*)
  let arg = int_of_string Sys.argv.(1) in (* in keyword is essential here*)
  print_int (fib arg);
  print_newline ();  (*removing () causes warning *)
  exit 0;;
main ();;      (*removing () here does not matter*)

Any explanation will be appreciated.

Upvotes: 1

Views: 77

Answers (1)

glennsl
glennsl

Reputation: 29106

OCaml is an expression-based language. It does not have statements, and therefore ; is not a statement terminator, but a sequence operator (similar to the comma operator of C). <expr1>; <expr2> is approximately just a short-hand for let () = <expr1> in <expr2>. It evaluates expr1, discards its value, then evaluates expr2 and returns that value.

let <pattern> = <expr1> in <expr2> is an expressions which binds the result of expr1 according to <pattern>, which may just be a simple identifier or a more complex record pattern for example, in the context of expr2. The bindings created by <pattern> will not exist outside expr2.

Using (), called "unit" in a binding defines a function. If you omit the argument, you're not defining a function, just a value. The difference is that a value is evaluated immediately, and just once, while a function will be evaluated when it is "called" by applying arguments to it. A function that expects () as an argument must be given () as the argument to execute it, otherwise you're just passing the function itself around. And if you're just discarding it, as you do above, that is almost always an error. Hence the warning.

In short:

  • let arg = int_of_string Sys.argv.(1); ... without an in separating two expressions is a syntax error. The compiler just doesn't realize it until it gets to the end of the current expression and discovers there is no in to be found there.

  • let main () =... defines a function

  • let main = ... defines a value

  • print_newline (); ... applies the argument () to print_newline, thereby executing it, then discards the return value

  • print_newline; ... doesn't really do anything

Finally, if you're just going to execute main once, you can reduce

let main () = ...;;
main;;

to

let () = ...;;

You don't need a named function unless you're going to use it multiple times.

Upvotes: 1

Related Questions