Как всегда сделать копию для аффектации? - PullRequest
2 голосов
/ 17 января 2012

Я определил модуль 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.На самом деле это и есть цель функции copy.Но есть ли способ позволить модулю всегда вызывать copy для affectation?

Чем хуже для функции let f (m: 'a matrix) = ..., любое изменение внутри f в m повлияет на внешнеепараметр, который прошел его значение до m.Есть ли способ избежать f, чтобы сделать это?

Ответы [ 2 ]

5 голосов
/ 17 января 2012

Вы можете легко определить теневые копии, например:

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
4 голосов
/ 17 января 2012

Когда вы пишете let m1 = m0, имена m1 и m0 обозначают один и тот же объект.Это не присвоение, это привязка значения к имени.Поскольку выражение после знака = является простым именем, оба имени m1 и m0 имеют одно и то же значение, связанное с ними.

Если вы хотите сделать копию изменяемой структуры данных,вы должны явно запросить эту копию.

Если вы хотите иметь возможность передавать данные без необходимости их изменения, эти данные должны быть неизменными.Это, действительно, является ключевой причиной для использования неизменных данных.Когда вы используете изменяемые данные, вам необходимо тщательно обдумать совместное использование между структурами данных и тем, кто отвечает за копирование при необходимости.

Хотя вы можете реорганизовать любую структуру данных, чтобы она была неизменной, плотные матрицы не являются примером, в котором неизменяемостьсияет, потому что неизменяемые представления плотных матриц, как правило, требуют гораздо больше памяти и больше времени обработки.

...