OCaml中let-bindings和references有什么区别?

6
OCaml教程说,引用是“真实变量”,你可以在程序中分配并更改它。但是let绑定并不具有相同的作用。在此链接中指出,当一个名称由let绑定设置时,您不能“重新分配它来指向另一个小部件”。我理解引用实际上存储在内存中而let绑定则没有,但我不明白他们关于赋值的说法。
在Ocaml交互会话中进行实验,似乎let绑定和引用具有相同的功能,只是语法有些不同。如果我使用let绑定将一个变量名称设置为某个整数值,则该名称将返回该值,直到我解除它或将名称重置为不同的整数,这是let绑定允许的。对于int、float和string类型都是如此,但我还没有尝试其他类型。我漏掉了什么吗?
# let let_var = 2;;
val let_var : int = 2
# let_var;;
- : int = 2
# let let_var = 3;;
val let_var : int = 3
# let_var;;
- : int = 3

1
在函数式编程和数学意义上,引用并不是真正的变量。请阅读https://existentialtype.wordpress.com/2012/02/01/words-matter/。 - camlspotter
1
请注意,引用并不一定会在内存中分配:非逃逸引用可以被编译器提升到寄存器中。 - gsg
2个回答

10

最好的观点是,在OCaml中,let绑定是将永久名称赋予某些东西的一种方式。由于OCaml的作用域规则允许您重新使用名称,因此可能会在内部上下文中再次给相同的名称赋值。但第一个名称从某种意义上仍然存在,并且仍与其永久值相关联。

这里有一个会帮助说明这一点的会话:

$ ocaml
        OCaml version 4.02.1

# let v = 12;;
val v : int = 12
# let g x = v + x;;
val g : int -> int = <fun>
# g 10;;
- : int = 22
# let v = 200;;
val v : int = 200
# g 10;;
- : int = 22
#
在这个会话中,有两个名称相同的不同let绑定“v”。函数“g”使用第一个绑定。如果您创建一个名为“v”的新绑定,则无法改变“g”的任何内容。
另一方面,引用是一个值。它根本不是名称,而是可变的一种值类型;即它保存了另一个可以更改的值。下面的会话可能有助于说明这一点:
# let myref = ref 12;;
val myref : int ref = {contents = 12}
# let h x = !myref + x;;
val h : int -> int = <fun>
# h 10;;
- : int = 22
# myref := 200;;
- : unit = ()
# h 10;;
- : int = 210

这里myref是一个"let-bound"变量,它永久引用一个值是一个引用(reference)。最初,该引用的值为12。但是该值可以更改。函数h使用引用中存储的当前值。但请注意(再次强调),myref没有改变。它仍然与相同的引用(即同一块内存)关联。


2
在我看来,let定义了一个变量,而OCaml中的所有变量都是不可修改的--简单地说,没有语法来给变量赋值。
有些变量是指向复合数据结构的指针,而某些数据结构是可变的(包括数组、字符串和具有mutable字段的记录/对象)。"引用"是最简单的可变数据结构,它是一个可变的单元格,在标准库的Pervasives中已经提供了与之一起工作的运算符;但在其他方面,它与其他可变数据结构并没有什么不同。
打个比方,就好像你在Java中,所有变量都是永远不变的final。然后你有一个数据结构Ref<T>,你可以使用new Ref<Integer>(...)来分配它,以获取对该对象的引用,并且可以使用.get().set()等方法访问其单个数据,并且可以将该数据结构的引用分配给其他变量,以便通过引用共享对该数据结构的更改。在OCaml中,ref发生的完全相同--你使用ref ...来分配它,以获取引用,然后使用!<-访问其单个数据,并且可以将该引用分配给其他变量,以便在引用之间共享对同一数据结构的视图。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接