Syntax extensions¶
Writing OCanren without syntax extensions¶
OCanren and original miniKanren consist of many syntax extension. There we describe how to write relation in OCanren without them, to make values of the obvious.
This is how we write relation without syntax extensions. The top of the input is techinal stuff for loading right packages into OCaml toplevel.
$ ocaml -stdin -impl - <<EOF
#use "topfind";;
#require "OCanren";;
#rectypes;;
open OCanren
open OCanren.Std
let rec appendo x y xy =
conde [
(x === Std.nil()) &&& (y === xy);
Fresh.three (fun h tl tmp -> (x === h % tl) &&& (appendo tl y tmp) &&& (xy === h % tmp))
]
EOF
This is how we use PPX exntesion to simplify code. It allows us
not to think about count of fresh varaibles
automatically insert
&&&
when creating fresh variables
$ ocaml -stdin -impl - <<EOF 4.13.1+flambda
#use "topfind";;
#require "OCanren";;
#rectypes;;
open OCanren
open OCanren.Std
#require "OCanren-ppx.ppx_fresh";;
let rec appendo x y xy =
conde [
fresh () (x === Std.nil()) (y === xy);
fresh (h tl tmp) (x === h % tl) (appendo tl y tmp) (xy === h % tmp)
]
EOF
There is also a camlp5 extension for simplifing relations described here.
PPX syntax extensions¶
PPX syntax extensions are not related to camlp5 and should be used, for example,
if you want decent IDE support. Main extensions are compilable by make ppx
ppx_repr¶
An analogue for logger library is called ppx_repr
(located at OCanren-ppx.ppx_repr package):
$ cat regression_ppx/test002repr.ml
let _ = REPR(1+2)
$ ./pp_repr.native regression_ppx/test002repr.ml
let _ = ("1 + 2", (1 + 2))
$ ./pp_repr.native -print-transformations
repr
ppx_fresh¶
An OCanren-specific syntax extension extension for creating fresh variables. It provides canonical miniKanren syntax from the Scheme
$ echo 'let _ = fresh (x) z' | dune exec ppx/pp_fresh.exe -- -impl -
let _ = Fresh.one (fun x -> delay (fun () -> z))
$ dune exec ppx/pp_fresh.exe -- -print-transformations
pa_minikanren
ppx_distrib¶
This extension is used to generate smart constructors and reifier from definition of our type. It optionally allows to decorate type definitions with deriving attributes which could be expanded later.
Below we use extension point with two type definitions. First one is nonrecursive fully abstract type. The extension with generate monadic fmap called fmapt for it. The second one is a specialization of previous type definition for our needs. it is uses to generate types for ground, logic, and injected values; reifier reify and exceptionful projection prj_exn from injected to logic/ground values; and smart constructor for creating values of injected type.
✗ dune exec ppx/pp_distrib.exe -- -impl - <<EOF
heredoc>[%%distrib
type nonrec 'a t =
| Z
| S of 'a
[@@deriving gt ~options:{ gmap; show }]
type ground = ground t]
heredoc> EOF
include
struct
type nonrec 'a t =
| Z
| S of 'a [@@deriving gt ~options:{ gmap; show }]
type ground = ground t[@@deriving gt ~options:{ gmap; show }]
type logic = logic t OCanren.logic[@@deriving gt ~options:{ gmap; show }]
type injected = injected t OCanren.ilogic
let fmapt a subj__002_ =
let open Env.Monad in
((Env.Monad.return (GT.gmap t)) <*> a) <*> subj__002_
let (prj_exn : (_, ground t) Reifier.t) =
let open Env.Monad in
let open Env.Monad.Syntax in
Reifier.fix (fun self -> OCanren.prj_exn <..> (chain (fmapt self)))
let (reify : (_, logic t OCanren.logic) Reifier.t) =
let open Env.Monad in
let open Env.Monad.Syntax in
Reifier.fix
(fun self ->
OCanren.reify <..>
(chain (Reifier.zed (Reifier.rework ~fv:(fmapt self)))))
let z () = OCanren.inji Z
let s _x__001_ = OCanren.inji (S _x__001_)
end
ppx_deriving_reify¶
Simplifies inline generation of reifiers for already known types.
$ dune exec ppx/pp_deriving_reify.exe -- -impl - <<EOF
let _ = [%reify: GT.int GT.list]
EOF
let _ = Std.List.reify OCanren.reify