Reputation: 24535
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
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