package um-abt

  1. Overview
  2. Docs
An OCaml library implementing unifiable abstract binding trees (UABTs)

Install

Dune Dependency

Authors

Maintainers

Sources

um-abt-v0.1.7.tbz
sha256=9472873b4f485ff1c169d950488133c79efb4b00b757526bfb14a2f043a0480f
sha512=e3ea3990177778ae109082bea0b952b760b4fc9a243f0321367d2927061e3766c0d99679c5e4b13f89532b22ad4993c34f91b625ec40e07f113b9812521f91f4

doc/um-abt/Abt/index.html

Module AbtSource

Overview

um-abt is a library for constructing and manipulating the abstract syntax of languages that use variables.

um-abt provides unifiable abstract binding trees (UABTs). An abstract binding tree (ABT) is an abstract syntax tree (AST), enriched with constructs to manage variable binding and scope.

um-abt extends ABTs with support for nominal unification (unificaiton modulo ɑ-equivalence).

Example

A succinct example of the typical use of this library can be seen in the following implementation of the untyped λ-calculus.

Define your language's operators:

 (* Define the usual operators, but without the variables, since we get those free *)
  module O = struct
    type 'a t =
      | App of 'a * 'a
      | Lam of 'a
    [@@deriving eq, map, fold]

    let to_string : string t -> string = function
      | App (l, m) -> Printf.sprintf "(%s %s)" l m
      | Lam abs    -> Printf.sprintf "(λ%s)" abs
  end

(Note the use of ppx_deriving to derive most values automatically.)

Generate your the ABT representing your syntax, and define combinators to easily and safely construct terms of your lanugage construct:

  (* Generate the syntax, which will include a type [t] of the ABTs over the operators **)
  open Abt.Make (O)

  (* Define some constructors to ensure correct construction *)

  let app m n : t =
    (* [op] lifts an operator into an ABT *)
    op (App (m, n))

  let lam x m : t =
    (* ["x" #. scope] binds all free variables named "x" in the [scope] *)
    op (Lam (x #. m))

Define the dynamics of your language (here using the variable substitution function subst, provided by the generated syntax):

  let rec eval : t -> t =
    fun t ->
    match t with
    | Opr (App (m, n)) -> apply (eval m) (eval n)
    (* No other terms can be evaluated *)
    | _                -> t

  and apply : t -> t -> t =
    fun m n ->
    match m with
    | Bnd (bnd, t)  -> subst bnd ~value:n t
    | Opr (Lam bnd) -> eval (apply bnd n)
    (* otherwise the application can't be evaluated *)
    | _             -> app m n

Enjoy unification and ɑ-equivalence:

  (* An example term *)
  let k = lam "x" (lam "y" x)

  (* The generated [Syntax] module includes a [Unification] submodule

     - the [=?=] operator checks for unifiability
     - the [=.=] operator gives an [Ok] result with the unified term, if its operands unify,
       or else an [Error] indicating why the unification failed
     - the [unify] function is like [=.=], but it also gives the substitution used to produce
       a unified term *)
  let ((=?=), (=.=), unify) = Unification.((=?=), (=.=), unify) in

  (* A free variable will unify with anything *)
  assert (v "X" =?= s);

  (* Unification is modulo ɑ-equivalence *)
  assert (lam "y" (lam "x" y) =?= lam "x" (lam "y" x));

  (* Here we unify the free variable "M" with the body of the [k] combinator,
     note that the nominal unification is modulo bound variables: *)
  let unified_term = (lam "z" (v "M") =.= k) |> Result.get_ok in
  assert (to_string unified_term = "(λz.(λy.z))");

Modules and interfaces

Sourcemodule type Operator = sig ... end

The interface for a module that defines the operators of a language

Sourcemodule Var : sig ... end

Variables, named by strings, which can be bound to a Var.Binding or left free.

Sourcemodule type Syntax = sig ... end

The interface of the family of UABTs representings a syntax

Sourcemodule Make (Op : Operator) : Syntax with module Op = Op

Make (Op) is a module for constructing and manipulating the Syntax of a language with Operators defined by Op.

OCaml

Innovation. Community. Security.