这是我打印出合并列表的简单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
,而{{1}}不是吗?
答案 0 :(得分:4)
;;
实质上是一种标记表达式结束的方式。在源代码中没有必要(尽管如果你愿意,你也可以使用它)。在顶层(OCaml REPL)中,它可用于评估您到目前为止输入的内容。没有这样的符号,顶层无法知道您是否打算稍后输入更多的表达式。
在您的情况下,它标记表示函数print_list
的主体的表达式的结尾。如果没有此标记,则以下符号看起来像是同一表达式的一部分,这会导致类型错误。
对于OCaml文件中的顶级表达式,我更喜欢编写如下内容:
let () = print_list (merge ( <= ) [1;2;3] [4;5;6])
如果您以这种方式编码,则无需在源文件中使用;;
令牌。
答案 1 :(得分:1)
这是杰弗里回答的扩展。
如您所知,在进行语言分析时,程序必须打破可管理的词汇元素中的流程,并期望这些所谓的lexemes(或令牌)遵循某些语法规则允许以更大的意义单位重新组合词汇。
在许多语言中,最大的语法元素是语句,它在指令和定义中多样化。在这些相同的语言中,语法的结构需要一个特殊的词汇来指示这些单元中的某些单元的结尾,通常是指令或语句。其他人使用lexeme来分离指令(而不是结束每个指令),但它基本上是相同的想法。
在OCaml中,语法遵循模式,这些模式在用于解析语言的算法中允许在各种情况下忽略这样的指令终止符(或分隔符)。例如,关键字let
始终是引入新定义所必需的。这可用于在程序语句的最外层(顶层)检测前一语句的结尾。
但是,您可以轻松地看到它引发的问题:Ocaml的交互式版本始终需要新语句的开头才能找出前一个语句,并且用户永远无法一个一个地提供语句!因此,;;
特殊标记被定义为(*)以指示顶级语句的结束。
(*):我实际上似乎记得这个令牌最初是在OCaml的祖先中,但是当OCaml被设计时它是可选的;但是,不要引用我的话。