如何使用ppxlib Ast_builder输出非多态变体?
问题解答
你当前用Ast_builder.Default.ptyp_variant生成多态变体是正常的——这个函数本身就是用来构建多态变体类型表达式(也就是带反引号的[A | B]形式)的。要生成常规变体,需要换一种方式:直接构建完整的类型定义结构,而非类型表达式。
解决方案代码
常规变体属于类型声明的一部分,需要通过Ptype_variant这个类型种类来定义,配合Ast_builder的类型声明、构造器声明助手函数实现:
let variant_type_stri ~loc defs = (* 生成每个变体构造器的声明 *) let constructors = List.map (fun (_, (def : Loader.t)) -> Ast_builder.Default.pconstructor_declaration ~loc ~name:{ txt = def.name; loc } ~args:Ppxlib.Pconstraint_tuple [] (* 无参数构造器,如需参数可修改这里 *) ~res:None ) defs in (* 生成类型声明 *) let type_decl = Ast_builder.Default.ptype_declaration ~loc ~name:{ txt = "t"; loc } ~params:[] ~cstrs:[] ~kind:(Ppxlib.Ptype_variant constructors) (* 指定为常规变体类型 *) ~private_:Ppxlib.Public ~attributes:[] in (* 生成类型定义的结构项 *) Ast_builder.Default.pstr_type ~loc Ppxlib.Recursive [type_decl]
然后生成模块的时候直接使用这个结构项:
Ast_builder.Default.pmod_structure ~loc [variant_type_stri ~loc defs]
效果验证
这样生成的模块就会包含常规变体类型,示例输出:
utop # module MyPalette = [%palette "colors.json"];; module MyPalette : sig type t = Aqua | Aquamarine1 | Aquamarine3 | Black | Blue | Blue1 | Blue3 end
关键说明
- 多态变体是类型表达式,可以直接作为类型使用(比如
let x : [A] =A);而常规变体是类型定义,必须通过type t = ...声明后才能使用。 - 如果你需要带参数的常规变体(比如
type t = Foo of int),只需要修改pconstructor_declaration的args参数,例如:~args:Ppxlib.Pconstraint_tuple [Ast_builder.Default.ptyp_int ~loc]
内容的提问来源于stack exchange,提问作者Anentropic
相关产品推荐
相关产品推荐

