Ocaml - 全局vs局部变量

时间:2016-10-19 19:52:36

标签: global-variables ocaml local-variables

我想创建一个名为result的全局变量,它使用5个字符串连接来创建一个包含字符串start的9倍的字符串,用逗号分隔。 我有两段代码,只有第二段代码声明了一个全局变量。 出于某种原因,它不能轻易地在我的脑中注册......难道只是因为我使用了一个let in,所以第一段代码的结果是一个局部变量?对此有更详细的解释吗?

let start = "ab";;

let result = start ^ "," in
  let result = result ^ result in
  let result = result ^ result in
  let result = result ^ result in
  let result = result ^ start in 
  result;;
- : string = "ab,ab,ab,ab,ab,ab,ab,ab,ab"

let result = 
  let result = start ^ "," in
  let result = result ^ result in
  let result = result ^ result in
  let result = result ^ result in
  let result = result ^ start in 
  result;;
val result : string = "ab,ab,ab,ab,ab,ab,ab,ab,ab"

3 个答案:

答案 0 :(得分:5)

让我成为一个有点无聊的人。 OCaml中没有本地和全局变量。这个概念来自具有不同范围规则的语言。此外,应谨慎使用“变量”一词。其含义被类C语言所歪曲。这个词的原始数学意义对应于某个数学对象的名称,该名称在公式内使用,表示一系列此类值。在类C语言中,变量与内存单元混淆,后者可能会随时间变化。因此,为了避免混淆,让我们使用更准确的术语。让我们使用单词 name 而不是变量。因为,变量......抱歉名称不是内存单元格,所以没有什么可以创建的。当您使用let语法之一时,实际上是在创建绑定,即名称和值之间的关联。 let <name> = <expr-1> in <expr-2>绑定<expr-2>表达式范围内的值。 let <name> = <expr-1> in <expr-2>本身也是一个表达式,因此,例如<expr-2>内部也可以包含let ... in ...构造,例如,

 let a = 1 in
   let b = a + 1 in
     let c = b + 1 in 
       a + b + c

我特别是,以非惯用方式缩进代码以突出表达式的句法结构。 OCaml还允许使用已在范围内绑定的名称。新绑定将隐藏现有绑定(例如,在C中不允许),例如,

  let a = a + 1 in
    let a = a + 1 in
      let a = a + 1 in
          a + a + a

最后,顶级(又称模块级别)let-binding(在OCaml用语中称为 definition )的语法为:let <name> = <expr>,请注意没有{{1 }} 这里。该定义将in绑定到词法范围中<name>的评估结果,该范围从定义点延伸到封闭模块的末尾。在实现模块时,必须使用<expr>将代码绑定到名称(可以使用let <name> = <expr>省略名称)。它与交互式顶层(交互式_程序)略有不同,它实际上接受一个表达式并对其进行求值。例如,

ocaml

不是有效的OCaml程序(可以放入let result = start ^ "," in let result = result ^ result in let result = result ^ result in let result = result ^ result in let result = result ^ start in result 文件并编译的东西)。因为它是表达式,而不是模块定义。

答案 1 :(得分:1)

  

是不是只使用了let in所以第一段代码的结果是局部变量?

差不多。定义全局变量的语法是let variable = expression,没有in。定义局部变量的语法是let variable = expression in expression,它将variable之后的表达式定义为in

答案 2 :(得分:0)

当您let ... in时,您将声明一个本地变量。如果您自己只有let(在模块的顶层),那么您将声明模块的全局名称。 (即,可以从模块导出的名称。)

您的第一个示例完全由let ... in组成。所以没有宣布顶级名称。

您的第二个示例本身有一个let,后面有几次出现let ... in。所以它声明了一个顶级名称result