Как изменить часть значений в записи? - PullRequest
3 голосов
/ 02 июля 2011

Я определил такой тип:

type s_program =
    { globals : s_var list;
      main: s_block; }
and s_var =
    { s_var_name: string;
      s_var_type: s_type;
      s_var_uniqueId: s_uniqueId }
and s_uniqueId = int

В точке моей программы у меня есть переменная p: s_program, но мне нужно изменить s_var_uniqueId каждого элемента p.globalsнапример, добавьте 1 к каждому s_var_uniqueId.У меня есть несколько вопросов:

1) Могу ли я напрямую изменить связанные значения в p, или мне нужно присвоить новые значения новому p':s_program

2) Могу ли я написатьчто-то в этом роде:

let p' = 
  { p with 
     globals = List.map (fun var -> { var with s_var_uniqueId = var.s_var_uniqueId + 1 }) p.globals

Большое спасибо.

Редактировать 1: исправить with деталь в соответствии с предложением

Ответы [ 2 ]

4 голосов
/ 02 июля 2011

Сначала вы можете прочитать этот раздел записи в OCaml и эту главу о модифицируемых структурах данных . Как уже говорилось, вы увидите, что записи не являются изменяемыми. Во-вторых, вам нужно подумать о том, что вы действительно хотите: изменяемая запись, запись с изменяемыми полями или изменяемая запись с изменяемыми полями. Например, предположим, что у нас есть запись для комплексных чисел (это тот же пример в ref 1 ).

type complex = { re:float; im:float } ;;

Если вы объявите что-то вроде

let c = {re=2.;im=3.} ;;

тогда вы не можете изменить ни c, ни re (или im). На самом деле c := {re=4.;im=6.} ;; или c.re := 4.;; оба не удастся с ошибкой. Чтобы получить изменяемую запись, вам просто нужно использовать ссылку для c.

let c = ref {re=2.;im=3.} ;;

Затем вы можете изменить c с помощью c := {re=4.;im=6.} ;;. Но я думаю, что вы хотите иметь изменяемое поле! Затем вы должны уточнить, какие поля являются изменяемыми. Предположим, что вы хотите, чтобы все поля были изменяемыми, вы можете написать

type complex = { re:float ref; im:float ref }
let make_complex r i = { re = ref r ; im = ref i } 
let c = make_complex 3. 4.
;;

и затем измените поля с помощью

c.re := 6. ; c.im := 7. ;;

Было бы проще с функцией типа float -> float -> ()

let change_re c r = c.re := r ;;
let change_im c i = c.im := i ;;
let change_complex c r i = change_re c r ; change_im c i ;;

Однако , я предлагаю вам по-настоящему подумать о том, чтобы добавить в свой код императивную функцию, подобную этой. Это может быть простой способ полностью разрушить его читабельность.

3 голосов
/ 02 июля 2011

1) Это зависит от того, хотите ли вы использовать Ocaml в качестве императивного или функционального языка программирования :).Если это первое, вы можете сделать оба поля записей изменяемыми (добавив ключевое слово mutable перед именем поля), а затем изменить их на месте.Однако я настоятельно советую не делать этого и:

2) придерживаться вашего второго подхода, который выглядит прекрасно (за исключением того, что вам не хватает {...} для второй модификации записи.

...