Error: This kind of expression is not allowed as right-hand side of `let rec'

I would like to suggest improving the error message and/or language documentation regarding this error.

I had some trouble understanding what was the problem with this function:

let copy_file1 src dest =
  let fi = open_in src in
  let fo = open_out dest in
  (* begin trouble *)
     let rec loop =
       let c = input_char fi
       in output_char fo c;
       loop
     in try loop
     (* end trouble *)

with
  | End_of_file ->
    close_in fi;
    close_out fo
  | e ->
    close_in fi;
    close_out fo;
    raise e

The compiler (ocamlc 4.14) gave me the message

Error: This kind of expression is not allowed as right-hand side of `let rec’

regarding the line let c = input_char fi, but I could not figure out what kind of expression it was that was not allowed (alternatively, what kind of expressions are allowed). I.e., “This kind” = ???

I was able to work around it by using a while statement instead of let rec.

However, I still wanted to know what was wrong with my let rec.

I studied the language documentation for let rec (1), but did not find anything helpful. It did not seem to say anything about the kind of expressions allowed, or not allowed, to be the right hand side of let rec.

Finally I found a couple of discussions here (2, 3) where people had encountered the same problem, and learned that my loop was not, as I thought, a function, because it had no parameters, and I should add an argument () to it to make it a function.

Since this error message has baffled me and at least two others , I would suggest either the error message could be improved (e.g., “Did you intend to define a recursive function? It needs at least one parameter.”), or the section 7 documentation on let rec could contain a warning to this effect, that functions need at least one argument. Or both.

Notes

  1. OCaml Manual, The OCaml language, sec. 7 Expressions, OCaml - The OCaml language

  2. Discussion " Why is this “let rec” rejected — but not if I add a
    superfluous parameter?",
    Why is this "let rec" rejected — but not if I add a superfluous parameter?

  3. Discussion “Recursive function”,
    Recursive function

1 Like

Actually, the manual contains a very precise specification of what is allowed in the right hand side of let rec (this documentation is linked from the page that you looked at, but perhaps it should be made to stand out more):

https://ocaml.org/releases/4.14/htmlman/letrecvalues.html

Cheers,
Nicolas

1 Like

IIIRC, the body of a letrec must have a functional time, viz. 'a -> 'b . So changing loop to loop() everywhere ought to fix the problem.

ETA: Oh wow, I didn’t realize you could use constructors in letrecs. Nice! (I guess I’m not surprised you can use lazy, since in my mind that’s a thin veneer over functions anyway).

Rewording the error message sounds like a good idea. The message should probably emphasizes more that it is recursive definitions of values that are subjects to strict rules (and not the more common and beginner-friendly recursive functions). Maybe something like:

Error: This kind of recursive definitions of non-functional values is not allowed.
The body of recursive value definitions cannot use the content of the values being defined.

It might be also a good idea to expose the reason why the definition was rejected which would also hint at the fact that the issue is that foo is not a function.

Error: This kind of recursive definitions of non-functional values is not allowed.
The contents of the value foo is used inside the definition of foo.

However, I am not sure if it is a good idea to add a hint about loop not being a function. My issue is that such hint would only be useful for beginners that are not yet familiar with function definitions. Outside of this audience, the hint is not useful and it might be mostly incorrect.

Concerning the manual, the local definition section mentions that ordinary recursive definitions should define only functions. The last paragraph of the sections also links to the recursive value extension .

2 Likes

Very good. But since the text including the link says

The current implementation also supports a certain class of recursive definitions of non-functional values, as explained in section 10.1

(emphasis mine), it is not likely to get the attention of a person who incorrectly thinks he is defining a recursive function.

The phrase “non-functional values” in your suggested revision of the error message would seem to imply that loop is not a function. Although, perhaps, not as plainly as a beginner would like.

How important is the beginner audience?

Would it really be likely to be mostly incorrect? When the name of the value (e.g. ‘loop’) is not followed by parameters, and the ‘=’ is not followed by ‘fun’ or ‘function’, wouldn’t it be pretty likely to be correct? (I am of course a beginner and could easily be overlooking some complication that is very obvious to you.)

Anyway, thanks for your attention to this matter!