在OCaml中的不可变记录或对象更新期间共享多少内存?

在OCaml中的不可变记录或对象更新期间共享多少内存?,ocaml,Ocaml,在OCaml中的不可变记录或对象更新期间,对象之间共享了多少内存?例如,对于代码中的记录: type foo = { a : int; b : int; c : int} let f1 = {a = 1; b=2; c=3} let f2 = {f1 with c=4} type ('i, 'j) lens = { get : 'j; set : 'j -> 'i } class bar = object val a = 1 method a =

在OCaml中的不可变记录或对象更新期间,对象之间共享了多少内存?例如,对于代码中的记录:

type foo = {
    a : int;
    b : int;
    c : int}

let f1 = {a = 1; b=2; c=3}
let f2 = {f1 with c=4}
type ('i, 'j) lens = { get : 'j; set : 'j -> 'i }
class bar = object
    val a = 1
    method a = {
        get = a;
        set = fun a' -> {< a = a' >}
    }
    val b = 2
    method b = {
        get = b;
        set = fun b' -> {< b = b' >}
    }
    val c = 3
    method c = {
        get = c;
        set = fun c' -> {< c = c' >}
    }
end
let b1 = new bar
let b2 = b1#c.set 4
f1
f2
之间共享了多少内存?基本上,它们是否为
a
b
共享内存?类似地,对于代码中的对象:

type foo = {
    a : int;
    b : int;
    c : int}

let f1 = {a = 1; b=2; c=3}
let f2 = {f1 with c=4}
type ('i, 'j) lens = { get : 'j; set : 'j -> 'i }
class bar = object
    val a = 1
    method a = {
        get = a;
        set = fun a' -> {< a = a' >}
    }
    val b = 2
    method b = {
        get = b;
        set = fun b' -> {< b = b' >}
    }
    val c = 3
    method c = {
        get = c;
        set = fun c' -> {< c = c' >}
    }
end
let b1 = new bar
let b2 = b1#c.set 4
type('i,'j)lens={get:'j;set:'j->'i}
类栏=对象
val a=1
方法a={
get=a;
set=fun a'->{}
}
val b=2
方法b={
get=b;
set=funb'->{}
}
val c=3
方法c={
get=c;
set=func'->{}
}
结束
设b1=新杆
设b2=b1#c,集4
b1
b2
之间共享了多少内存


基本上,想象一下这样一种情况:字段
a
b
c
非常非常大。我想做一个不可变的更新,但如果可能的话,我不想复制所有的内存。

对于记录,
f1
f2
之间没有共享内存,因为
int
占用的内存与指针一样多。如果您有更复杂的对象而不是
int
,则会有共享内存。 例如在

type foo = {
  a : int list;
  b : int list;
  c : int list;
}

let f1 = {a = [1; 1; 1]; b = [2; 2; 2]; c = [3]}
let f2 = {f1 with c = [4]}
1和2的列表将在两个记录之间共享

Ocaml中的一般规则是复制简单类型(
int
char
bool
,…),但共享复杂类型(
'a list
'a array
,…)。这就是为什么不变的数据结构很好:您可以轻松地共享。但请注意,数据是共享的,即使它是可变的:

type foo = {x : int ref; y : int ref}
let a = {x=ref 0; y = ref 0}
let b = {a with y = ref 1}
let () = b.x := 2

那么
a.x
等于
2

int-ref?这是对另一个对象的显式间接寻址,使简单int成为“复杂类型”并因此共享。通常,在记录中,您只需使用mutable关键字,在这种情况下,简单类型仍然是简单类型,不共享。这实际上节省了内存。我知道在记录中使用
int-ref
不是可变
int
的正确方法,我只想给出一个可变数据结构的简单示例(而
int-ref
是我想到的最简单的可变数据结构)这与您的问题无关,但如果您要定义功能记录字段,则使用
let rec
定义它们可以共享它们的关闭环境。这在react中用于最小化节点的内存占用,请参见@DanielBünzli,我对此很感兴趣,但不完全了解其工作原理。代码
typefoo={a:int->int;b:int->int;c:int->int}let z=3让f1={a=(funx->x+z);b=(funx->x+z+1);c=(funx->x+z+2)}让f2={f1和c=(funx->x+z+3)}让rec f3={f1和c=(funx->x+z+4)}
共享任何闭包吗?基本上,
let rec
需要在哪里?除非您事先已经知道更新的定义,否则您将无法对更新执行任何操作,但例如对于
f1
,如果您提起函数定义,请命名它们,通过一个let rec来定义它们,它们都将共享一个包含
z
@DanielBünzli的值的闭包环境好吧,如果我理解正确的话,类似于下面的工作:
typefoo={a:int->int;b:int->int;c:int->int}让z=3让rec a x=x+z让rec b x=x+z+1让rec c x=x+z+2让rec d x=x+z+3让f1={a;b;c}让f2={f1 with c=d}
基本上,
a
b
c
都是在
let rec code>之外定义的,因此都可以共享相同的闭包?另外,为什么行为不同于普通的
let
?不,它是
let rec a x=。。。和Bx=。。。和cx=…
。但是请注意,这是一个编译器实现细节。如果您懂一些法语,您可以阅读闭包的不同编译权衡。