【问题标题】:OCaml delimiters and scopesOCaml 分隔符和范围
【发布时间】:2010-06-13 16:00:26
【问题描述】:

我正在学习 OCaml,尽管我在命令式编程语言(C、C++、Java)方面拥有多年经验,但在 OCaml 语法中的声明或表达式之间的分隔符方面遇到了一些问题。

基本上我知道我必须使用; 来连接表达式,并且序列返回的值将是最后使用的表达式之一,例如,如果我有

exp1; exp2; exp3

它将被视为返回exp3 值的表达式。从这里开始我可以使用

let t = something in exp1; exp2; exp3

应该没问题吧?

什么时候应该使用双分号;;?究竟是什么意思?

为了避免语法错误,我必须使用其他分隔符吗?

我给你举个例子:

let rec satisfy dtmc state pformula = 
  match (state, pformula) with
    (state, `Next sformula) ->
        let s = satisfy_each dtmc sformula
        and adder a state = 
            let p = 0.; 
            for i = 0 to dtmc.matrix.rows do
                    p <- p +. get dtmc.matrix i state.index
            done;
            a +. p
        in
            List.fold_left adder 0. s
      | _ -> []

它给了我| 的语法错误,但我不明白为什么......我错过了什么?这是一个经常发生的问题,我必须尝试许多不同的解决方案,直到它突然起作用:/

一个附带的问题:用let 声明而不是let .. in 将定义一个var 绑定,该绑定在它被定义后持续存在?

我基本上要问的是:我必须使用哪些分隔符以及何时必须使用它们。此外,在使用解释器 ocaml 而不是编译器 ocamlc?

时,我应该考虑哪些差异

提前致谢!

【问题讨论】:

    标签: syntax ocaml delimiter


    【解决方案1】:

    ;; 定界符终止顶级实体。在 ocaml 顶层(解释器)中,它向解释器发出信号,表明特定的输入片段已完成并应进行评估。

    在使用ocamlcocamlopt 编译的程序中,您不需要它的频率接近,因为连续的顶级let(没有in),moduletypeexception 和类似的语句自动表示新“短语”的开始。如果您在一个模块中包含一个顶级表达式,该表达式仅针对其副作用进行评估(例如生成一些输出或注册一个模块),您需要一个 ;; 在它之前告诉编译器停止编译前一个短语并开始编译一个新事物。否则,如果之前的东西是let,它将假定新的表达式是let 的一部分。例如:

    let msg = "Hello, world";; (* we need ;; here *)
    print_endline msg;; (* ;; is optional here, unless we have another expression *)
    

    当你需要和不需要;; 时有点微妙,所以我通常用它来终止我的所有模块级实体,这样我就不必担心何时需要和不需要它。

    ; 用于分隔单个表达式中的连续“语句”。所以foo; bar是由foobar组成的单个顺序表达式,而foo;; bar只在模块的顶层有效,表示两个表达式。

    在没有inlet 上:该构造仅在模块定义中有效,因此绑定的变量将绑定到模块的末尾。通常,这只是文件的结尾;但是,如果您有嵌套模块,则其范围可能会受到更多限制。它在另一个表达式或定义(例如函数定义)中不起作用,除非它在本地模块定义中。

    【讨论】:

      【解决方案2】:
      let p = 0.; 
      

      这是错误。 ; 必须是 in。不能在没有in 的情况下使用let 仅用于定义全局函数,不能在表达式中使用它。

      一个附带问题:用 let 声明 let .. in 将定义一个 var 绑定,该绑定在定义后持续存在?

      您只能使用其中一种(在交互式解释器中允许混合表达式和定义除外)。定义全局函数或值时,需要let 而没有in。在表达式中,您需要 letin

      【讨论】:

      • 我在发布我的代码之前尝试过。但是当我尝试let p = 0. in for ... done; a +. p 时,它告诉我 for 循环内部的p 未绑定。这就是我变得疯狂的原因.. 它不应该是无约束的,因为它的形式是let something in exp1; exp2。它应该知道 for 循环内的something:/
      【解决方案3】:

      ;;ocamlREPL中用于终止输入并开始解释,与ocamlcocamlopt编译时没有特殊意义。

      您不能使用 &lt;- 运算符分配任意值,您必须使用 ref 类型的可变变量:

      let p = ref 0. in
      for i = 0 to dtmc.matrix.rows do
          p := !p +. get dtmc.matrix i state.index
      done;
      a +. !p
      

      【讨论】:

      • 好的,现在它越来越清晰了。多亏了你们两个……每个人都 +1 :) 问题是当你混合错误并且你无法理解真正发生的事情时,OCaml 与我习惯的完全不同,并且没有可用的“备忘单”。 .
      • ;; ocamlc/ocamlopt 与 REPL 中的含义相同 - 用于分隔顶级短语。确实,在处理语法错误以明确标记每个顶级定义的结尾并查看编译器是否同意时非常有用:)
      猜你喜欢
      • 2016-07-04
      • 1970-01-01
      • 2014-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多