我对编写这样的代码通常不满意:
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魔法会让我完全消除它。
答案 0 :(得分:2)
这很简单:只需使用闭包进行设置,并编写一个函数来抽象出样板文件
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)
...
等等。
如果你使用像Jane这样的宏包,你可以做得更好 街头的fieldlib。这会产生一流的领域 自动生成的setter和getter。这意味着你 不必每次都手工构建闭包。
答案 1 :(得分:1)
理论上你能逃脱的最短时间是:
frobnicate (function
| 0x01 -> gets , a_record_uuid
| 0x02 -> gets , a_group
...
)
当然,你会被OCaml挫败,因为1°在Objective 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
...
答案 2 :(得分:0)
我对编写像这样的代码一般不满意
如果你问我,这是一个好品味的标志: - )
我知道没有魔法,但我认为最好的方法是拆分样板:
每个可变字段的一个样板设定函数。可能在不同的情况下有用。
将整数代码映射到“如何处理此字段”的一种数据结构
您可以使用表格而不是函数来实现记录扫描程序。下面是一个暗示性的例子。
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