Types 在OCaml中分解产品类型分配
我通常不满意这样编写代码:Types 在OCaml中分解产品类型分配,types,ocaml,product,boilerplate,Types,Ocaml,Product,Boilerplate,我通常不满意这样编写代码: 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 = g
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
让load\u record\u字段游标获取geti gett a=函数
|0x01->让c,s=gets()在a.a_记录中,让c,s=gets()在a.a_组中,让c,s=gets()在a.a_标题中,让c,s=gets()在a.a_用户名中,让c,t=gett()在a.a_创建时间`结束_记录光标
我已经最小化了样板文件,但我想知道是否有任何OCaml魔法可以让我完全消除它。理论上,你能逃脱的最短时间是:
frobnicate (function
| 0x01 -> gets , a_record_uuid
| 0x02 -> gets , a_group
...
)
当然,您将被OCaml阻止,因为在目标Caml中没有“指向成员的指针”构造,所以您必须编写fun a s->a.a_record\u uuid
我通常不满意这样编写代码
如果你问我,这是一种良好品味的标志:-)
我不知道什么是魔法,但我认为最好的办法是把样板分割开来:
为每个可变字段提供一个样板设置器函数。在不同的上下文中可能有用
一个将整数代码映射到“如何处理此字段”的数据结构
您可以使用表而不是函数来实现记录扫描程序。
在这里,get
和gett
之间的区别是一个真正的问题。
在下文中
sf
代表“字符串字段”
tf
代表“时间域”
eor
代表“记录结束”
为了适合我的例子,我制作了表格
和查找
;使用任何有效的数据结构
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
这非常简单:只需使用闭包进行设置,然后编写一个函数来提取样板文件
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)
...
让load\u record\u字段游标获取geti gett a x=
让弗罗布准备好=
让(c,s)=进入()
设置s;`More_记录c
在里面
功能
|0x01->frob gets(fun s->a.a_记录_uuid frob gets(fun s->a.a_组frob gett)(fun s->a.a_标题)注意,正是因为引用是一级值,“引用而不是可变字段”方法完全改变了{existing_record with a_uuid=…}
语法。正是因为这个原因,我更喜欢使用setter函数。@Pascal:的确如此。另一方面,如果您有可变字段,那么无论如何都应该非常小心地使用该语法。这似乎是对一个简单问题的一个相当复杂的答案。在实践中,存在类型在这方面没有起到重要作用。缺少的一点是在OCaml中是一流的记录字段,尽管使用现有的camlp4宏可以很容易地添加这些字段。
let t = t a in
match
| 0x01 -> t gets a_record_uuid
| 0x02 -> t gets a_title
...
let t read reference = let c, x = read () in reference := x ; `More_record c
match
| 0x01 -> t gets a.a_record_uuid
...
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
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)
...