问题
In my OCaml program, I spend considerable time wring "to_string" for variant types over and over again. Either I need them for debugging purpose, or because I need a specific formatted output.
So far, they follow a template such as follows:
let rec to_string = function
| Var x -> x
| Implies (f1, f2) -> Printf.sprintf "(=> %s %s)" (to_string f) (to_string f2)
| And (f1, f2) -> Printf.sprintf "(& %s %s)" (to_string f1) (to_string f2)
| Or (f1, f2) -> Printf.sprintf "(| %s %s)" (to_string f1) (to_string f2)
| Not (f) -> Printf.sprintf "(~ %s)" (to_string f)
| True -> "#t"
| False ->"#f"
I'm wondering if there are more convenient/conventional ways of than this, possibly with the latest development of the language. For instance, automatic generation of templates based on the type? generic printing functions that could be used for debugging?
One way advocated in "Real World OCaml" is to use the Sexp module of the Core library that provides facilities for this very purpose. It seems to work well if you don't need much customization about how you print the values. I'd like to know if there are other/better options.
回答1:
There're few type-based generators, that you may found interesting, like deriving
, typerep
, sexplib
, etc. But I do not expect, that there is something magical, that will read your mind on compile time and write a pretty-printing functions according to your taste and feelings. What concerning templating, then all of the templating engines are some kind of pattern-matching, (usually stringly typed), and OCaml already provides you pattern-matching out of box. And also do not forget, that your type definition is recursive and this makes template based approaches much harder to use. You can use some automatic json
or xml
based dumper, like ocaml-cow
and implement some kind of xslt transformation, but you will end up with lots of code, that are actually reinventing OCaml's native pattern matching.
So, for small languages, like yours, writing this to_string
functions is the best solution. I think that this is the most natural way to express your idea to computer. I would also suggest to use Format
module, and recurse using %a
specifiers. Also, Format
module, has concepts of tags
. Tags allows to literally tag pieces of text in format strings,
the format of tagging can be explained with the following example:
@{<html>@{<head>@{<title>Tags!@}@}@{<body>Hello!@}@}
This can be automatically transferred to HTML:
<html>
<head>
<title>
Tags!
</title>
</head>
<body>
Hello!
</body>
</html>
One can also, transfer it to LaTeX
, json
, or anything else, including to nothing (i.e., ignoring tags at all). But Tags are more about handling formatting and meta information, like syntax higlighting and referencing. They can't actually influence on concrete syntax.
For rich syntax trees the approach of writing recursive set of pretty-printing function doesn't scale well. And that's why there is O in the OCaml. You can use open recursion to implement AST-visitor clasess with lots of hooks (i.e., methods). This is the approach that is used in OCaml itself and camlp4.
来源:https://stackoverflow.com/questions/28527501/printing-variant-types-in-ocaml