Можно ли обобщить обновления полей записей в OCaml?
Вопрос
Я очень начинающий программист OCaml, поэтому, пожалуйста, простите меня, если это глупый / очевидный вопрос.Там есть очень много чтобы усвоить, и я, возможно, пропустил это в документации.
У меня есть база кода, которая начинает выглядеть примерно так:
let update_x p x =
add_delta p;
p.x <- x;
refresh p
let update_y p y =
add_delta p;
p.y <- y;
refresh p
let update_z p z =
add_delta p;
p.z <- z;
refresh p
Дублирование начинает меня беспокоить, потому что я хотеть написать что-то вроде этого:
let update_scalar p scalar value =
add_delta p;
magic_reflection (p, scalar) <- value;
refresh p
Таким образом, когда я обновляю x, я могу просто вызвать:
update_scalar p 'x' value
Это вызывает у меня "макросы!", но я не верю, что в OCaml есть макросистема.Что еще я могу сделать?
Решение
Нет, вы не можете делать то, что хотите, в обычном OCaml.Вы могли бы написать расширение синтаксиса с помощью camlp4 (это своего рода макросистема, хотя и другого типа, чем вы, вероятно, привыкли), которая трансформировала бы
UPDATE_FIELD x f y
в
x.f <- y
В качестве альтернативы, вы могли бы поместить данные в хэш-таблицу и отказаться от безопасности типов.
ПРИМЕЧАНИЕ:Версия camlp4, включенная в OCaml версии 3.10 и более поздних версий, отличается от предыдущей версии и несовместима с ней.Дополнительные сведения о последней версии см. в разделе обучающий сайт OCaml.
Другие советы
Вы не можете делать то, что вы хотите, но вы можете значительно уменьшить шаблон с помощью функции более высокого порядка:
let update_gen set p x =
add_delta p;
set p x;
refresh p
let update_x = update_gen (fun p v -> p.x <- v)
let update_y = update_gen (fun p v -> p.y <- v)
let update_z = update_gen (fun p v -> p.z <- v)
В OCaml есть макросистема (camlp4), и она позволяет вам реализовывать подобные вещи с некоторой работой.
Как отмечалось выше, в ocaml есть макросистема. И для этой задачи нужна только небольшая часть:
open Printf
type t = { mutable x : float; mutable y : float; mutable z : float; mutable t : int; }
let add_delta p = p.t <- p.t + 1
let refresh p = printf "%d) %.2f %.2f %.2f\n" p.t p.x p.y p.z
DEFINE UPD(x) = fun p v ->
add_delta p;
p.x <- v;
refresh p
let update_x = UPD(x)
let update_y = UPD(y)
let update_z = UPD(z)
let () =
let p = { x = 0.; y = 0.; z = 0.; t = 0; } in
update_x p 0.1;
update_y p 0.3;
update_z p 2.0
Скомпилировать с помощью
ocamlfind ocamlc -package camlp4.macro -syntax camlp4o q.ml -o q
Смотрите сгенерированный код с помощью:
camlp4o Camlp4MacroParser.cmo q.ml