aboutsummaryrefslogblamecommitdiffstats
path: root/lib/world.mli
blob: 0a3bb9a5c17ae39d94826e09e7203c72caef2025 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                                                    


                                                                    



                                           







                                                                    











                                                                 










                                                                    



















                                                                                  











                                                                  







                                                                    
                                                                               
                                                              


                                                                    
                                                                   


                                                                   
   
(** Worlds: the store of relations, and the loader that builds the
    standalone one.

    Decision 4 of the integration document: the VM is parameterized
    over a world. This module gives the module type every host
    satisfies, the standalone in-memory world, and the loader that
    admits a parsed program into it. Admission is where totality is
    enforced: a program that gets a world is a program whose queries
    terminate. *)

(** A compiled relational expression: what rule bodies and queries
    are made of after names are resolved. [Exists] is lowered away
    at loading: its variable is renamed apart and the form becomes a
    conjunction. *)
type expr =
  | Apply of string * Pattern.t Label.Map.t
  | And of expr * expr
  | Or of expr * expr
  | Not of expr * expr
      (** [u :not d]: the universe holds and the denial has no
          solutions. Decidable negation only: the VM runs the denial
          once its variables are ground. *)
  | Forall of expr * expr
      (** Every solution of the quantifier satisfies the body. The
          VM runs it when the quantifier is decidable, which keeps
          universals off infinite domains. *)

type rule = {
  rule_name : string;
  head : Pattern.t Label.Map.t;
  body : expr;
  witness : Label.t option;
      (** For a recursive rule, the label whose argument strictly
          decreases. The VM requires it ground before unfolding,
          which is what turns the admission proof into runtime
          termination. [None] on non-recursive rules. *)
}

(** The primitive host-checked domains. *)
type primitive = D_integer | D_natural | D_rational | D_string

(** What a schema constrains an attribute by: a primitive domain, or
    a membership criterion, an arbitrary relational expression with
    exactly one free variable, the subject, bound to the attribute
    value at admission. Foreign keys are the criterion
    [([Department id: D])], nothing more special than that. *)
type domain =
  | Primitive of primitive
  | Criterion of { subject : string; body : expr }

(** How a relation is defined. *)
type def =
  | Table of { schema : (Label.t * domain) list; facts : Term.t Label.Map.t list }
      (** Extensional: a schema and finite stored tuples. *)
  | Rules of rule list  (** Intensional: defined by admitted rules. *)

(** What a host must answer for the VM to run: which relation lives
    under a name. Builtins are the VM's own and are not consulted
    here. *)
module type WORLD = sig
  type t

  val find : t -> string -> def option
end

type error

val pp_error : Format.formatter -> error -> unit

(** A fact attribute awaiting a criterion check. The loader cannot
    run the solver (the solver sits above it), so criterion
    admission is finished by {!Program}, against the fully loaded
    world. *)
type pending = {
  pending_relation : string;
  pending_label : Label.t;
  pending_body : expr;
      (** The criterion with its subject already bound to the
          attribute value; admissible iff it has a solution. *)
}

(** The standalone world: an immutable catalog loaded from program
    text. This is Sol as a separate language; there are no branches,
    no transitions, only the pure fragment. *)
module Standalone : sig
  type t

  val find : t -> string -> def option

  val load : Ast.statement list -> (t * expr list * pending list, error) result
  (** Admits a program: registers relations, checks every fact
      against its schema and primitive domains, compiles rules and
      queries, and enforces totality. Rejected, not deferred: a
      recursive rule without a structural decrease witness, a mutual
      recursion cycle, an unknown relation, or an ill-typed fact is
      an [error], and no world exists. Returns the world, the query
      expressions in program order, and the criterion checks for
      {!Program} to finish. *)
end