Вопрос

Я вообще не согласен с написанием кода, как это:

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 и добавьте его.

Я вообще недоволен таком написанием кода

Признак хорошего вкуса, если вы спросите меня :-)


Я не знаю о магии, но я думаю, что лучший путь - разделить шаблон:

  1. Одна функция сбора шаблона для каждого изменяемого поля. Может быть полезен в разных контекстах.

  2. Одна структура данных для картирования целочисленных кодов «что делать с этим полем»

Вы можете реализовать свой сканер записей, используя таблицу вместо функции. Появляется наводящий пример. Разница между 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top