我有一个ocaml类型:
type t = A | B | ...
和打印有关该类型的东西的函数:
let pp_t fmt x = match x with
| A -> Format.fprintf fmt "some nice explanations about A"
| B -> Format.fprintf fmt "some nice explanations about B"
| ...
我怎么能写一个函数来打印所有的解释?相当于:
的东西let pp_all_t fmt =
Format.fprintf fmt A;
Format.fprintf fmt B;
...
但如果我忘记添加新的构造函数,那会警告我。
有一些自动构建该功能的东西会更好,
因为我的问题是t
很安静并且变化很大。
我无法想象如何在类型构造函数上“迭代”,但也许有一个技巧......
编辑:我最后做的是:
type t = A | B | ... | Z
let first_t = A
let next_t = function A -> B | B -> C | ... | Z -> raise Not_found
let pp_all_t fmt =
let rec pp x = pp_t fmt x ; try let x = next_t x in pp x with Not_found -> ()
in pp first_t
所以当我更新t
时,编译器警告我必须更新pp_t
和next_t
,并且pp_all_t
不必更改。
感谢大家的建议。
答案 0 :(得分:2)
为了解决复杂和不断发展的类型的问题,实际上我可能会编写一个OCaml程序,该程序从包含值列表和相关信息的文件生成代码。
但是,如果你有一个函数incr_t : t -> t
增加了t
类型的值,并且如果你让t的第一个和最后一个值保持不变,你可以写下以下内容:
let pp_all_t fmt =
let rec loop v =
pp_t fmt v;
if v < Last_t then loop (incr_t v)
in
loop First_t
在OCaml中不能有一般的多态incr_t
,因为它只适用于构造函数为nullary的类型(不带值)。但是你可以为任何给定的类型编写自己的incr_t
。
这种事情在Haskell中得到了很好的处理。基本上,当定义非常明显时,编译器会为您编写一些函数。 OCaml有一个名为deriving的类似项目。我从来没有使用它,但似乎确实处理了枚举值的问题。
既然你说你想要一个“技巧”,如果你不介意使用OCaml的不安全部分(我个人做介意),你可以写下incr_t
如下:
let incr_t (v: t) : t =
(* Please don't use this trick in real code :-) ! See discussion below.
*)
if t < Last_t then
Obj.magic (Obj.magic v + 1)
else
failwith "incr_t: argument out of range"
如果可能的话,我尽量避免使用这种代码,这太危险了。例如,如果类型t
获取带值的构造函数,它将产生无意义的值。真的是“等待发生的事故”。