This library implements a framework for datatype-generic programming in Objective Caml language.
The key feature of the approach in question is object-oriented representation of transformations performed over regular algebraic datatypes. Our implementation supports polymorphic variants; in particular, a transformation for a "joined" polymorphic variant type can be acquired via inheritance from the transformations for its counterparts.
opam pin add GT https://github.com/PLTools/GT.git -y
or from the main opam repository
opam update
opam install GT -y
Use findlib package GT.ppx
in combination with ppxlib
. See ppxlib
's manual for full guidance. In short do
# #use "topfind";;
# #require "GT";;
# #require "GT.ppx_all";;
../GT/ppx_all: added to search path
../GT/ppx_all/./ppx.exe --as-ppx: activated
# type 'a list = Nil | Cons of 'a * 'a list [@@deriving gt ~options:{fmt; show}];;
type 'a list = Nil | Cons of 'a * 'a list
class virtual ['ia, 'a, 'sa, 'inh, 'extra, 'syn] list_t :
object
method virtual c_Cons : 'inh -> 'extra -> 'a -> 'a list -> 'syn
method virtual c_Nil : 'inh -> 'extra -> 'syn
end
val gcata_list :
('a, 'typ0__003_, 'b, 'c, 'typ0__003_ list, 'd) #list_t ->
'c -> 'typ0__003_ list -> 'd = <fun>
class ['a, 'b] show_list_t :
(unit -> 'a -> string) ->
(unit -> 'a list -> string) ->
object
constraint 'b = 'a list
method c_Cons : unit -> 'a list -> 'a -> 'a list -> string
method c_Nil : unit -> 'a list -> string
end
class ['a, 'b] fmt_list_t :
(Format.formatter -> 'a -> unit) ->
(Format.formatter -> 'a list -> unit) ->
object
constraint 'b = 'a list
method c_Cons : Format.formatter -> 'a list -> 'a -> 'a list -> unit
method c_Nil : Format.formatter -> 'a list -> unit
end
val fmt_list :
(Format.formatter -> 'a -> unit) -> Format.formatter -> 'a list -> unit =
<fun>
val list :
(('a, 'b, 'c, 'd, 'b list, 'e) #list_t -> 'd -> 'b list -> 'e,
< fmt : (Format.formatter -> 'f -> unit) ->
Format.formatter -> 'f list -> unit;
show : ('g -> string) -> 'g list -> string >,
(('h -> 'i list -> 'j) -> ('k, 'i, 'l, 'h, 'i list, 'j) #list_t) ->
'h -> 'i list -> 'j)
GT.t = {GT.gcata = <fun>; plugins = <obj>; fix = <fun>}
val show_list : ('a -> string) -> 'a list -> string = <fun>
Use findlib package GT.syntax.all
to enable extension and all built-in plugins. To compile and see the generated code use the following command:
ocamlfind opt -syntax camlp5o -package GT.syntax.all regression/test081llist.ml -dsource
To preprocess only the code in this library (for example, a test) use the following shell command:
dune exec camlp5/pp5+gt+plugins+o.exe regression/test005.ml
To use camlp5 (>= 7.12) syntax extension in toplevel try (after installation) this:
# #use "topfind.camlp5";;
# #camlp5o;;
# #require "GT.syntax";;
# #require "GT.syntax.all";;
# @type t = GT.int with gmap,show;; (* for example *)
- The framework for generation is in
common/
. The generic plugin for adding new transformations is incommon/plugin.ml
. - All built-in plugins live in
plugins/
and depend on the stuff incommon/
. - Camlp5-specific preprocessing plugin lives in
camlp5/
. Depend on stuff incommon/
. - PPX-specific preprocessing plugin lives in
ppx/
. Depends on stuff incommon/
. - Built-in plugins that represent transformations live in
plugins/
. Depends oncommon/
. - A library for built-in types and transformations for types from Pervasives live in
src/
. Depends on syntax extension fromcamlp5/
and plugins fromplugins/
.
ppxlib
camlp5
ocamlgraph
for topological sortingocamlbuild
as build system
make
to compile whole library.make && make tests
to compile regression tests too.
In case some of the tests do not compile use following commands to see generated code:
- with camlp5 use
dune exec camlp5/pp5+gt+plugins+o.exe regression/test817logic.ml
- with PPX use
dune exec ppx/pp_gt.exe regression/test801mutal.ml
To build documentation set the environment variable GT_WITH_DOCS
and run opam install odoc --yes && dune build @doc
.
The generated HTML files will be located at _build/default/_doc/_html/index.html
.
In the following section we describe our approach in a nutshell by a typical example.
Known to be not supported or not taken to account:
- non-regular recursive types
- GADTs
Can be a bug:
- Method
on_record_declaration
doesn't introduce new pattern names systematically - For
compare
andeq
plugins in case of ADT with single constructor we generate unreachable pattern matching pattern that gives a warning.
Improvements:
- Documentation for
src/GT.ml
is not generated (possible because of a macro). - Better signature for
method virtual on_record_constr
. - Custom transformation functions for type parameters has become broken after introducing combinatorial interface for type abbreviations.
- Allow
[@@named "..."]
attribute to provide a custom name for non-latin constructors (like lists). - Sometimes we need override class definition for a plugin. It should be possible to specify new custom class inside the attribute.
- Dmitry Kosarev, Dmitry Boulytchev. Generic Programming with Combinators and Objects // submitted to ML workshop 2018
- Dmitry Boulytchev. Code Reuse with Object-Encoded Transformers // A talk at the International Symposium on Trends in Functional Programming, 2014.
- Dmitry Boulytchev. Code Reuse with Transformation Objects // unpublished.
- Dmitry Boulytchev. Combinators and Type-Driven Transformers in Objective Caml // submitted to the Science of Computer Programming.