我通常对编写这样的代码不满意:

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。这产生一流的领域,随着 自动生成setter和getter。这意味着你 就不必用手每次构建闭合。

其他提示

理论上你可以逃脱最短的是:

frobnicate (function 
| 0x01 -> gets , a_record_uuid 
| 0x02 -> gets , a_group 
  ...
)

当然,你会被OCaml中因为1°没有“指针构件”在目的CAML构建挫败,所以你将不得不写入fun a s -> a.a_record_uuid <- s代替a_record_uuid(至少是)和2°的类型系统不完全支持存在量化,以便该函数的返回类型不能预期的:

  

exists 'a. int -> (unit -> record * 'a) * ('a -> record -> unit)

我想你可以通过具有以创纪录的设定值命名的功能解决了1°,如果你碰巧做往往不够:

type complex = { re : int ; im : int }
let re r c = { c with re = r }
let im r c = { c with im = i }

这是一个有点非正统的,我想,但它通常以后得到回报,因为我往往在大多数情况下,功能使用它们。您可以创建在命令行式风格的等效,或者你可以接受一个函数的开销(只增加了大约20个字符)。

As或2°,它可以通过隐藏存在量词在函数解决:

let t e read write = let c, x = read () in write x e ; `More_record c

这会让你去到:

let t = t a in
match 
  | 0x01 -> t gets a_record_uuid 
  | 0x02 -> t gets a_title
  ...

我也不会,如果CamlP4支持某种糖分配功能的惊讶。在此同时,如果你使用的引用,而不是可变域,可以缩短这个了(因为引用是第一类值,字段都没有):

let t read reference = let c, x = read () in reference := x ; `More_record c

match 
  | 0x01 -> t gets a.a_record_uuid
  ...

我通常对编写这样的代码不满意

如果你问我的话,这是高品味的标志:-)


我不知道有什么魔法,但我认为最好的方法是拆分样板:

  1. 每个可变字段都有一个样板设置器函数。在不同的情况下可能有用。

  2. 一种将整数代码映射到“如何处理该字段”的数据结构

您可以使用表而不是函数来实现记录扫描器。下面是一个提示性示例。和...之间的不同 getsgett 这是一个真正的问题。接下来,

  • sf 代表“字符串字段”
  • tf 代表“时间场”
  • eor 代表“记录结束”

我已经弥补了 tabulatelookup 适合我的例子;使用任何有效的数据结构。

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