如何总是制作一个矫揉造作的副本?

时间:2012-01-16 22:47:01

标签: arrays module matrix reference ocaml

我已经定义了一个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 listmap定义矩阵。我只需要更改此模块,而不是使用此模块的代码。

但我意识到的一个问题是,如果我let m1 = m0 in ...m1m0将共享相同的实体项目:m1的任何更改都会影响m0 1}}。实际上这是copy函数的目的。但有没有办法让模块始终为copy调用affectation

功能let f (m: 'a matrix) = ...越糟糕,fm内的任何更改都会影响将其值超过m的外部参数。有没有办法避免f这样做?

2 个答案:

答案 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时,名称m1m0表示同一个对象。这不是赋值,它是值与名称的绑定。由于=符号后面的表达式是一个简单名称,因此m1m0两个名称都绑定了相同的值。

如果要复制可变数据结构,则必须明确请求该复制。

如果您希望能够传递数据而不必修改它,则此数据必须是不可变的。实际上,这是使用不可变数据的关键原因。当您使用可变数据时,您需要仔细考虑数据结构之间的共享以及负责在需要时进行复制的人员。

虽然你可以将任何数据结构重新组织为不可变的,但是密集矩阵不是不可变性的例子,因为密集矩阵的不可变表示往往需要更多的内存和更多的处理时间。