我已经定义了一个Matrix
模块,如下所示:
module Matrix =
struct
type 'a matrix = 'a array array
let make (nr: int) (nc: int) (init: 'a) : 'a matrix =
let result = Array.make nr (Array.make nc init) in
for i = 0 to nr - 1 do
result.(i) <- Array.make nc init
done;
result
let copy (m: 'a matrix) : 'a matrix =
let l = nbrows m in
if l = 0 then m else
let result = Array.make l m.(0) in
for i = 0 to l - 1 do
result.(i) <- Array.copy m.(i)
done;
result
...
然后我可以编写例如let mat = Matrix.make 5 5 100
的代码。定义Matrix
模块的优点是隐藏其组件的类型。例如,我稍后可能想要使用'a list list
或map
定义矩阵。我只需要更改此模块,而不是使用此模块的代码。
但我意识到的一个问题是,如果我let m1 = m0 in ...
,m1
和m0
将共享相同的实体项目:m1
的任何更改都会影响m0
1}}。实际上这是copy
函数的目的。但有没有办法让模块始终为copy
调用affectation
?
功能let f (m: 'a matrix) = ...
越糟糕,f
到m
内的任何更改都会影响将其值超过m
的外部参数。有没有办法避免f
这样做?
答案 0 :(得分:5)
您可以轻松定义卷影副本,其中包括:
type 'a m =
| Shared of 'a matrix
| Matrix of 'a array array
and 'a matrix = {
mutable m : 'a m;
}
let copy_matrix m = [... YOUR CODE FOR COPY ...]
(* Shadow copy *)
let copy matrix =
{ m = Shared matrix }
let rec content m =
match m.m with
| Shared m -> content m
| Matrix m -> m
let write m x y k =
let c = match m.m with
| Shared matrix ->
(* Break the shared chain & copy the initial shared matrix *)
let c = copy_matrix (content matrix) in
m.m <- Matrix c;
c
| Matrix m -> m in
c.(x).(y) <- k
答案 1 :(得分:4)
当您撰写let m1 = m0
时,名称m1
和m0
表示同一个对象。这不是赋值,它是值与名称的绑定。由于=
符号后面的表达式是一个简单名称,因此m1
和m0
两个名称都绑定了相同的值。
如果要复制可变数据结构,则必须明确请求该复制。
如果您希望能够传递数据而不必修改它,则此数据必须是不可变的。实际上,这是使用不可变数据的关键原因。当您使用可变数据时,您需要仔细考虑数据结构之间的共享以及负责在需要时进行复制的人员。
虽然你可以将任何数据结构重新组织为不可变的,但是密集矩阵不是不可变性的例子,因为密集矩阵的不可变表示往往需要更多的内存和更多的处理时间。