如何在OCaml中定义符号?

问题描述

我正在尝试为我在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