Ocaml 使用Cmdliner时,是否有方法对记录中的参数进行分组?

Ocaml 使用Cmdliner时,是否有方法对记录中的参数进行分组?,ocaml,Ocaml,假设我有以下代码 让main a b c d e=Format.eprintf”%b%b%b%b%B@.“a b c d e 让cmd= 让我们进去 将a=Arg.(值&标志&信息[“a”]~doc:“a”)放入 将b=Arg.(值、标志和信息[“b”]~doc:“b”)放入 将c=Arg.(值、标志和信息[“c”]~doc:“c”)放入 设d=Arg.(值&标志&信息[“d”]~doc:“d”)在 将e=Arg.(值、标志和信息[“e”]~doc:“e”)放入 术语。(const main$a

假设我有以下代码

让main a b c d e=Format.eprintf”%b%b%b%b%B@.“a b c d e
让cmd=
让我们进去
将a=Arg.(值&标志&信息[“a”]~doc:“a”)放入
将b=Arg.(值、标志和信息[“b”]~doc:“b”)放入
将c=Arg.(值、标志和信息[“c”]~doc:“c”)放入
设d=Arg.(值&标志&信息[“d”]~doc:“d”)在
将e=Arg.(值、标志和信息[“e”]~doc:“e”)放入
术语。(const main$a$b$c$d$e),术语。(信息“test”~版本:“1”~文档:“abcde”~退出:默认退出~man:[])
let()=Cmdliner.Term。(退出@@eval cmd)
如果我在没有选项的情况下执行我的程序,我将获得
false
,如果我将它与
-ade
一起使用,我将获得
true-false-true
,这正是我想要的

现在,假设我在
main
函数中输入了一个拼写错误,然后改为编写

(*注意c*前面的d)
让main a b d c e=Format.eprintf“%b%b%b%b”B@.“a b c d e
如果我像以前一样使用
-ade
执行主程序,我将获得
true-false-true
,这可能被认为是错误的

所以,我想知道的是,是否有可能在记录中收集选项,并将它们与它们的专有名称一起使用,比如下面的示例(这不起作用):

opencmdliner
类型o={a:bool Term.t;
b:布尔项t;
c:布尔项t;
d:布尔项t;
e:bool Term.t;}
(*a-e不是布尔值,而是布尔项,它给出了一个明显的错误*)
让main{a;b;c;d;e}=Format.eprintf“%b%b%b%b%B@.“a b c d e
让cmd=
将a=Arg.(值&标志&信息[“a”]~doc:“a”)放入
将b=Arg.(值、标志和信息[“b”]~doc:“b”)放入
将c=Arg.(值、标志和信息[“c”]~doc:“c”)放入
设d=Arg.(值&标志&信息[“d”]~doc:“d”)在
将e=Arg.(值、标志和信息[“e”]~doc:“e”)放入
设o=Term.const{a;b;c;d;e}in
Term.(const main$o),Term.(信息“test”~版本:“1”~文档:“abcde”~退出:默认退出~man:[])
let()=Cmdliner.Term。(退出@@eval cmd)

这在大型项目上可能很有用,并且可以减少函数的参数数量。也许有一种方法可以做到这一点,但我找到的所有例子都使用了第一种方法。我不想在github页面上打开一个问题,所以我在这里问它

如果为记录类型编写字段更新函数,则可以非常直接地完成此操作。例如,如果我们有

type arg = { a:bool; b:bool; c:bool; d:bool; e: bool }

let main {a;b;c;d;e} = Format.eprintf "%B %B %B %B %B@." a b c d e

module Update = struct
  let a a r = { r with a }
  let b b r = { r with b }
  let c c r = { r with c }
  let d d r = { r with d }
  let e e r = { r with e }
end
唯一缺少的步骤是将直接提供参数的
Cmdliner.Term.t
转换为更新arg类型记录的术语。一项实施将是:

let cmd =
  let open Cmdliner in
  (* first the starting record *)
  let start = Term.const { a = false; b=false; c=false; d=false; e=false } in
  let transform r (update,arg) = 
    Term.( const update $ arg $ r ) in
  let arg =
    List.fold_left transform
      start
      Update.[
        a, Arg.(value & flag & info ["a"] ~doc:"a");
        b, Arg.(value & flag & info ["b"] ~doc:"b");
        c, Arg.(value & flag & info ["c"] ~doc:"c");
        d, Arg.(value & flag & info ["d"] ~doc:"d");
        e, Arg.(value & flag & info ["e"] ~doc:"e");
    ] in
  Term.(const main $ arg),
  Term.info "test"
     ~version:"1"
     ~doc:"abcde"
     ~exits:Term.default_exits
     ~man:[]

let () = Cmdliner.Term.(exit @@ eval cmd)

我真的很喜欢你的解决方案,但问题是它让我创造了一个与cmdliner理念背道而驰的首发记录。这就是为什么我没有找到解决问题的方法,因为我想找到一种方法,从
'a Cmdliner.Term.t
记录到
'a
记录。