Consider the following trivial bit of OCaml:
open Printf let _ = let array_max arr = let arr' = Array.copy arr; Array.sort (fun a b -> b - a) arr'; arr'.(0) in printf "max=%d\n" (array_max [|1;2;3;4;5|])
To me as a beginner this looks quite plausible, since I wrote something much like it, of course it should actually be:
let arr' = Array.copy arr in
But the error from the compiler is strange:
make -k ocamlc -g -c testcase.ml File "testcase.ml", line 9, characters 0-0: Error: Syntax error make: *** [testcase.cmo] Error 2 make: Target `testcase' not remade because of errors
That is actually one character beyond the end of my file!
So my top tip for today is, mysteriously vague error messages like this are probably a
; instead of an
in somewhere. Emacs to the rescue:
M-x replace-regexp RET \(let.*\); RET \1 in RET
Hah! Now if only I could think of a way to invoke that automagically when I get
I hate it, too. The error messages of the ocaml compiler are often not very helpful. Another common error that produce confusing error messages is a “;” at the end of a function (instead of ‘;;’ or no semicolon at all)
Another annoying thing is that the compiler always stops at the first error. Other compilers can show further error messages in the same run,…
btw array_max without copying and more generic:
let array_max arr = Array.fold_left max arr.(0) arr
or better something like:
let array_max = function
| [||] -> raise (Invalid_argument "array_max")
| arr -> Array.fold_left max arr.(0) arr
Cool, thanks for the tip! I think I actually did it with
Array.to_listthen sorted it and did
hdbut I needed an example for the error.
I have to say, the Haskell compiler is much more helpful, tho’ in its own way it can be just as obscure sometimes 🙂
-pp camlp4o yields a more useful error message. Also better use
let () =instead of
let _ =in this case.
Ah, that is much nicer:
ocamlc -g -custom -annot -pp camlp4o -o test test.ml
File "test.ml", line 8, characters 44-45:
Parse error: "in" expected after [binding] (in [expr])
I shall certainly add this to my standard Makefile template, thanks!
What’s the difference between
let _ =and let () = ? Do they both not mean, discard the results of this computation, I just want the side effects?
# let f x = let _ = x in ();;
val f : 'a -> unit =
# let f x = let () = x in ();;
val f : unit -> unit =