问题描述
我正在尝试为我在OCaml项目中定义的类型定义符号。基本上,此类型使我可以表达一个类型的一个或两个值,因此我将其称为maybe_pair
。我希望能够写一些符号来定义这种类型的值,例如:
- 对于单个值,我们可以写
<5> : int maybe_pair
- 对于两个值,我们可以写
<3;7> : int maybe_pair
我基本上是在尝试模仿列表符号的工作方式,但是我相信这可能是不可能的。
解决方法
仅通过定义OCaml函数就无法获得所需的符号。您可以将<
和>
定义为中缀运算符(具有固定的预定义优先级),但是不能将它们定义为像括号一样成对使用。
您可以使用OCaml语法扩展机制ppx获得任何所需的语法。但这是一个很大的主题,对于在StackOverflow上给出答案(对于我来说)来说太大了。
您可以在此处阅读有关PPX的信息:https://ocamlverse.github.io/content/ppx.html
在这里:https://github.com/ocaml-ppx/ppxlib
,下面的类型可以容纳类型revoke token
的一个或两个值:
'a
,
尽管不支持带有尖括号的表示法,但您可以编写ppx-rewriter来部分实现目标。
我假设该对定义如下:
(* file: pair.ml *)
type 'a maybe_pair = MkPair of 'a * 'a option [@@deriving show]
然后ppx扩展名应如下所示:
(* file: ppx_pair.ml *)
open Ppxlib
let name = "mp"
let expand ~loc ~path:_ expr =
match expr with
| {pexp_desc = Pexp_sequence (e1,e2); _} -> [%expr Pair.MkPair ([%e e1],Some [%e e2]) ]
| e1 -> [%expr Pair.MkPair ([%e e1],None) ]
let ext =
Extension.declare name Extension.Context.expression
Ast_pattern.(single_expr_payload __)
expand
let () = Driver.register_transformation name ~extensions:[ext]
我们可以看到它在运行中,如下所示:
let () =
let x = [%mp 1] in
Format.printf "x is %a\n" (Pair.pp_maybe_pair Format.pp_print_int) x;
let x = [%mp 1; 2] in
Format.printf "x is %a\n" (Pair.pp_maybe_pair Format.pp_print_int) x
输出:
x is (Pair.MkPair (1,None))
x is (Pair.MkPair (1,(Some 2)))
我在这里做了一个最低限度的示例项目结构: https://gitlab.com/gopiandcode/example-ppxlib