Факторинг назначений типа продукта в OCAML
-
23-09-2019 - |
Вопрос
Я вообще не согласен с написанием кода, как это:
let load_record_field cursor gets geti gett a = function
| 0x01 -> let c, s = gets () in (a.a_record_uuid <- s; `More_record c)
| 0x02 -> let c, s = gets () in (a.a_group <- s; `More_record c)
| 0x03 -> let c, s = gets () in (a.a_title <- s; `More_record c)
| 0x04 -> let c, s = gets () in (a.a_username <- s; `More_record c)
| 0x07 -> let c, t = gett () in (a.a_creation_time <- t; `More_record c)
.
.
.
| 0xFF -> `End_of_record cursor
Я минимизировал шаблон, но мне было интересно, есть ли какая -то магия OCAML, которая позволила бы мне полностью устранить ее.
Решение
Это мертвые просто: просто используйте закрытие, чтобы сделать настройку и написать функцию, чтобы абстрагировать шаблон
let load_record_field cursor gets geti gett a x =
let frob get set =
let (c,s) = get () in
set s; `More_record c
in
function
| 0x01 -> frob gets (fun s -> a.a_record_uuid <- s)
| 0x02 -> frob gets (fun s -> a.a_group <- s)
| 0x03 -> frob gett (fun s -> a.a_title <- s)
...
и так далее.
Вы можете сделать это еще лучше, если вы используете пакет макросов, такой как Fieldslib Jane Street. Это генерирует первоклассные поля, наряду с автоматически сгенерированными сеттерами и геттерами. Это будет означать, что вам не придется каждый раз строить закрытие вручную.
Другие советы
Приложение консоли автоматически не добавляет ссылку на System.Windows.forms.dll.
Щелкните правой кнопкой мыши проект в проводнике решений и выберите «Добавить ссылку ...», а затем найдите System.Windows.Forms и добавьте его.
Я вообще недоволен таком написанием кода
Признак хорошего вкуса, если вы спросите меня :-)
Я не знаю о магии, но я думаю, что лучший путь - разделить шаблон:
Одна функция сбора шаблона для каждого изменяемого поля. Может быть полезен в разных контекстах.
Одна структура данных для картирования целочисленных кодов «что делать с этим полем»
Вы можете реализовать свой сканер записей, используя таблицу вместо функции. Появляется наводящий пример. Разница между gets
а также gett
здесь настоящий кикер. В следующем,
sf
означает «Строковое поле»tf
означает «Поле времени»eor
означает "конец записи"
Я придумал tabulate
а также lookup
по своему примеру; Используйте любую эффективную структуру данных.
let sf set a c = let c, s = gets() in (set a s; `More_record c)
let tf set a c = let c, s = gett() in (set a t; `More_record c)
let eor a c = `End_of_record c
let fields = tabulate
[ 0x01, sf a_record_uuid
; 0x02, sf a_group
; ...
; 0x07, tf a_creation_time
; ...
]
let load_record_field cursor gets geti gett a code = lookup fields code cursor a