由双分号

时间:2017-12-31 21:04:33

标签: syntax-error ocaml

我很抱歉在这里提出这样一个基本问题,但在尝试编译以下代码时出现语法错误,

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;通过在每个函数定义的末尾添加;;而不是;来解决此语法错误。

我在某个地方错过了分号吗?

1 个答案:

答案 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代码中不需要它,除非你混合使用你不应该的顶级定义和​​表达式。

但是,

;;对于初学者来说仍然可以作为“隔板”使用。如果只在文件中间放置一个;;代替;,您会发现编译器现在指向错误位置。那是因为;;在没有前面的表达式完成的情况下终止了定义。所以你现在知道之前有一个错误。 (实际上在前面的表达式中,但由于你的整个文件是一个单独的表达式,“在那之前”是我们能做的最好的事情)。