我很抱歉在这里提出这样一个基本问题,但在尝试编译以下代码时出现语法错误,
let sum_of_squares_of_two_largest x y z =
let a :: b :: _ = List.sort (fun x y -> -(compare x y)) [x; y; z] in
a * a + b * b;
let rec factorial n =
if n = 0 then 1 else n * factorial (n - 1);
let e_term n = 1.0 /. float_of_int (factorial n);
let rec e_approximation n =
if n = 0 then (e_term 0) else (e_term n) +. (e_approximation (n - 1));
let rec is_even x = if x = 0 then true else is_odd (x - 1);
and is_odd x = not (is_even x);
let rec f_rec n =
if n < 3 then n else f_rec(n - 1) + 2 * f_rec(n - 2) + 3 * f_rec(n - 3);
无信息编译器告诉我第19行有语法错误,这是文件的最后一行。
File "source.ml", line 19, characters 0-0:
Error: Syntax error
也就是说,第19行是一个空行,只有一个换行符。
我可以&#34;修复&#34;通过在每个函数定义的末尾添加;;
而不是;
来解决此语法错误。
我在某个地方错过了分号吗?
答案 0 :(得分:3)
正如评论中指出的那样,;
不是像许多其他(Algol启发的)语言中的语句终止符,而是序列运算符。它需要两个值,抛弃第一个(但如果它不是单位则发出警告)并返回第二个值。因此,a; b
大致相当于let _ = a in b
。
你说你本来期望错误说';' is missing the second operand.
之类的东西,但问题是:它没有。直到它到达文件的末尾(此时错误消息肯定可能更加智能,但可能不是很准确)。
代码中每个;
后面的内容看起来像一个可能产生值的完全有效的表达式。例如,如果let rec factorial n = ...;
已let rec factorial n = ... in 2
,则表达式的值将为2
。从编译器的角度来看,这里的问题是它在表达式完成之前用完了文件。
正如您所知,;;
实际上是一个语句终止符。或许顶级定义终结符是一个更好的术语(我不知道它是否有正式名称)。它在REPL中用于终止输入,但在普通的OCaml代码中不需要它,除非你混合使用你不应该的顶级定义和表达式。
;;
对于初学者来说仍然可以作为“隔板”使用。如果只在文件中间放置一个;;
代替;
,您会发现编译器现在指向错误位置。那是因为;;
在没有前面的表达式完成的情况下终止了定义。所以你现在知道之前有一个错误。 (实际上在前面的表达式中,但由于你的整个文件是一个单独的表达式,“在那之前”是我们能做的最好的事情)。