package ppx_deriving_morphism
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=7af4d13a54045dee2665977e88e393e4db34543b16a5cef9a86137499c23e565
md5=d26eab20880bf39724c3b839c8015701
README.md.html
ppx_deriving_morphism
Deriving Morphisms for arbitrary OCaml data structures
This package provides a plugin for ppx_deriving that generates morphisms in the style of the ast_mapper in the ocaml source tree for arbitrary data structures (with a clear focus on syntax trees).
Usage
Consider a typical small functional language:
type expr =
| Abs of unit binding
| App of app
| Let of expr binding
| Var of string
| Int of int
and app = {
lhs: expr;
arg: expr;}
and 'a binding = {
var: string;
rhs: 'a;
bdy: expr;}[@@deriving (folder, mapper)]
The last line generates folder
and mapper
routines:
type 'b folder =
{
fold_binding: 'a . ('a -> 'b -> 'b) -> ('b,'a binding) fold_routine;
fold_app: ('b,app) fold_routine;
fold_expr: ('b,expr) fold_routine;
on_expr: 'b expr_folder;}
and ('a,'b) fold_routine = 'a folder -> 'b -> 'a -> 'a
and 'b expr_folder =
{
fold_Abs: ('b,unit binding) fold_routine;
fold_App: ('b,app) fold_routine;
fold_Let: ('b,expr binding) fold_routine;
fold_Var: ('b,string) fold_routine;
fold_Int: ('b,int) fold_routine;}
type mapper =
{
map_binding: 'a . ('a -> 'a) -> ('a binding,'a binding) map_routine;
map_app: (app,app) map_routine;
map_expr: (expr,expr) map_routine;
on_expr: expr_mapper;}
and ('a,'b) map_routine = mapper -> 'a -> 'b
and expr_mapper =
{
map_Abs: (unit binding,expr) map_routine;
map_App: (app,expr) map_routine;
map_Let: (expr binding,expr) map_routine;
map_Var: (string,expr) map_routine;
map_Int: (int,expr) map_routine;}
There is also an automatically generated identity_folder
and identity_mapper
which only traverse the structure.
To implement a typical operation, one can now "extend" these default implementations:
let fv_folder = { identity_folder with
fold_binding =
(fun f self {var;rhs;bdy} ->
self.fold_expr self bdy %>
filter var %>
f rhs ) ;
on_expr = { identity_folder.on_expr with fold_Var = (fun self -> cons) }
}
Obviously the benefit is bigger for more specialized operations (free variables is a good example, since it is not affected by many constructors in the language. Another example would be capture-avoiding substitution (for a mapper
).
Limitations
At this early stage, the implementation has some limitations:
Currently, there is no way to derive a signature for a folder or a mapper
The fact that there needs to be a name of the morphism-records means that only one folder and mapper can be derived for each module
Only constructors in the recursive group are considered by the automatically generated folder and mapper