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)
      ...