Why is this "let rec" rejected — but not if I add a superfluous parameter?

Beginner with little programming experience here, learning Ocaml by myself. Please let me know if this is the wrong forum to ask such a question:

Why does the compiler reject

let rec enterX =
  print_string "Enter X:\n";
  if read_line () = "X" then print_string "Well done!\n"
  else ( print_string "That's not X! Try again!\n"; enterX )

with the message This kind of expression is not allowed as right-hand side of `let rec’?

While if I add a superfluous parameter k like so:

let rec enterX k =
  print_string "Enter X:\n";
  if read_line () = "X" then print_string "Well done!\n"
  else ( print_string "That's not X! Try again!\n"; enterX 3)

everything is fine?

rec defines the following function definition as recursive.
In the first case it is not a function definition (as there are no arguments).
In the second case it is (of type (int -> unit)).
Here it would make more sense to put () instead of k as argument.

Apparently there is some extension on that though :
http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s%3Aletrecvalues

Thanks! The documentation indeed excludes that recursive definition, but leaves me wondering why.

So an idiomatic way of writing that program would be

let rec enterX () =
print_string “Type the letter X and hit enter:\n”;
if read_line () = “X”
then print_string “Well done!\n”
else ( print_string “That’s not X! Try again!\n”; enterX () )

?

The main difference between let rec enter () = <body> and let rec enter = <body> is that the first definition is a function, while the last is a value - datum. If you want something to be called recursively it should be a function. If you want something to be constructed infinitely, like an infinite list, then it should be a value. Note, it is a very rare case when you need the latter, usually, you need the former, a recursive function, that defines a process. Hope this helps!

1 Like