这是为了什么 ';;'在 OCaml 中?

What's it for ';;' in OCaml?

这是我打印合并列表的简单 OCaml 代码。

let rec merge cmp x y = match x, y with
    | [], l -> l
    | l, [] -> l
    | hx::tx, hy::ty ->
        if cmp hx hy
            then hx :: merge cmp tx (hy :: ty) 
            else hy :: merge cmp (hx :: tx) ty

let rec print_list = function 
    | [] -> ()
    | e::l -> print_int e ; print_string " " ; print_list l 
    ;;


print_list (merge ( <= ) [1;2;3] [4;5;6]) ;;

我从 Print a List in OCaml 复制了 print_list 函数,但我必须添加 ';;'在函数实现之后以避免此错误消息。

File "merge.ml", line 11, characters 47-57:
Error: This function has type int list -> unit
       It is applied to too many arguments; maybe you forgot a `;'.

我的问题是为什么';;' print_list 需要而 merge 不需要?

;;本质上是一种标记表达式结束的方式。它在源代码中不是必需的(尽管您可以根据需要使用它)。它在顶层(OCaml REPL)中很有用,可以对您目前输入的内容进行评估。没有这样的符号,顶层无法知道您稍后是否要输入更多的表达式。

在您的例子中,它标记了表示函数主体的表达式的结尾 print_list。没有这个标记,下面的符号看起来像是同一个表达式的一部分,这会导致类型错误。

对于 OCaml 文件中的顶级表达式,我更喜欢这样写:

let () = print_list (merge ( <= ) [1;2;3] [4;5;6])

如果您以这种方式编码,则无需在源文件中使用 ;; 标记。

这是 Jeffrey 回答的扩展。

如您所知,在进行语言解析时,程序必须打破可管理的 词法 元素的流程,并期望这些所谓的 lexemes (或标记)遵循某些句法规则,允许以更大的意义单位重新组合词素。

在许多语言中,最大的句法元素是语句,它的指令和定义多种多样。在这些相同的语言中,语法结构需要一个特殊的词位来指示其中一些单元的结尾,通常是指令或语句。其他人使用词素来分隔指令(而不是结束每个指令),但它基本上是相同的想法。

在 OCaml 中,语法遵循在用于解析语言的算法中允许在各种情况下省略此类指令终止符(或分隔符)的模式。例如,关键字 let 始终是引入新定义所必需的。这可用于在程序语句的最外层(顶层)检测前面语句的结尾。

但是,您可以很容易地看到它引发的问题:Ocaml 的交互式版本总是需要一个新语句的开头才能找出前一个语句,而用户永远无法提供一个语句一个! ;; 特殊标记因此被定义为(*) 以指示顶级语句的结束。


(*):我其实好像记得token最初是在OCaml的祖先中,但后来在设计OCaml时变成了可选的;但是,请不要引用我的话。