Geolog DSL Structure
This directory contains example .geolog files that use a richer DSL than the
minimal .ech script language in examples/scripts/.
These files are reference material and experiments. They are not currently
wired into the query-engine binary, REPL, SQL parser, or planner pipeline.
This README summarizes the Geolog DSL structure as it appears in the examples in this directory. It should be read as a practical, example-driven reference, not as a formal or complete language specification.
At a Glance
- Top-level declarations are
theoryandinstance. - The main kind of type is
Sort. - Symbols can denote sorts, constants, functions, predicates, or nested instances.
- Axioms use sequent-style syntax:
premise |- conclusion. - Instance bodies can be plain literals (
= { ... }) or chase blocks (= chase { ... }). - Function application is postfix, and qualified names use
/.
Informal File Shape
file := { comment | theory_decl | instance_decl }
comment := // ...
theory_decl :=
theory theory_params? Name {
theory_item*
}
instance_decl :=
instance Name : theory_app = {
instance_item*
}
| instance Name : theory_app = chase {
instance_item*
}
In practice, a file is usually a sequence of theory declarations followed by one or more example instances.
Top-Level Declarations
theory
A theory introduces sorts, symbols, and axioms.
theory Graph {
V : Sort;
Edge : [src: V, tgt: V] -> Prop;
}
Theories may also be parameterized.
theory (X : Sort) (Y : Sort) Iso {
fwd : X -> Y;
bwd : Y -> X;
}
theory (N : PetriNet instance) Marking {
token : Sort;
token/of : token -> N/P;
}
Observed parameter forms:
- sort parameters:
(X : Sort) - instance parameters:
(N : PetriNet instance) - dependent instance parameters:
(RP : N ReachabilityProblem instance)
instance
An instance provides concrete elements and assignments for a theory.
instance Triangle : Graph = {
A : V;
B : V;
C : V;
}
Instances may target parameterized theories by writing the arguments before the theory name.
instance MyMap : MyBase Map = { ... }
instance solution0 : ExampleNet problem0 Solution = { ... }
instance AB_Iso : As/a Bs/b Iso = { ... }
Theory Body Items
The examples show the following declaration forms inside a theory body.
Sort declarations
V : Sort;
E : Sort;
This introduces carrier sorts.
Constants or distinguished elements
elem : X;
This introduces a named element of an existing sort.
Functions
src : E -> V;
fwd : X -> Y;
token/of : token -> N/P;
Names may contain /, which is used heavily for structured or qualified names.
Predicates and relations
Unary predicates:
completed : Item -> Prop;
Record-shaped predicates:
Edge : [src: V, tgt: V] -> Prop;
depends : [item: Item, on: Item] -> Prop;
Product-valued functions
Functions may return record-shaped values.
pair_of : A -> [left: B, right: C];
W/src : W -> [firing: F, arc: N/out];
Nested instance slots
Theories can contain fields whose values are themselves instances.
initial_marking : N Marking instance;
trace : N Trace instance;
initial_iso : (trace/input_terminal) (RP/initial_marking/token) Iso instance;
Axioms
Axioms use a sequent-like form.
ax/trans : forall x, y, z : V.
[src: x, tgt: y] Path, [src: y, tgt: z] Path |- [src: x, tgt: z] Path;
An axiom declaration has the observed structure:
name : forall binders. premise |- conclusion;
Formula and Term Syntax
The examples use the following building blocks inside axioms and assignments.
Quantifiers
Universal binders appear after forall.
forall x : X, y : Y.
Existentials appear directly inside conclusions or disjuncts.
exists r : R. r R/data = [x: a, y: b]
exists w : W. w W/src_firing = f, w W/src_arc = arc
Sequents
The central connective is |-, separating premise from conclusion.
premise1, premise2 |- conclusion1, conclusion2;
In the examples:
- commas act as conjunctions
- the left side is the premise
- the right side is the conclusion
Equality
Equality is used for ordinary values and compound values.
ab src = A
r R/data = [x: a, y: b]
x fwd bwd = x
Truth constants
|- true;
|- false;
Disjunction
Disjunction is written as \/.
[item: x, on: y] depends |- x blocked \/ y completed;
Predicate atoms
Unary predicate atoms:
x blocked
y completed
Record-shaped predicate atoms:
[src: x, tgt: y] Edge
[a: x, f: i] id
Postfix application
Function application is postfix and can be chained.
e src
x id
x fwd bwd
w W/src_arc N/out/tgt
This is one of the most distinctive traits of the DSL.
Qualified paths
The slash / is used for qualification and nested access.
Observed examples include:
R/data
N/P
N/out/src
trace/input_terminal
RP/initial_marking/token
ExampleNet/A
Record literals
Records are written with brackets and named fields.
[x: a, y: b]
[firing: f, arc: arc]
The examples also show positional shorthand for record arguments when the field order is known:
[e, e] mul = e;
[cook_dinner, on: buy_groceries] depends;
Field projection
Record-valued terms support field projection.
r R/data .x = a
Instance Body Items
The examples show the following forms inside instance bodies.
Element declarations
a : V;
tok : token;
ab : T;
Function assignments
ab src = A;
tok token/of = ExampleNet/A;
a1 map = MyBase/b1;
Predicate facts
Unary facts:
buy_groceries completed;
Record-shaped facts:
[src: a, tgt: b] Edge;
[item: x, on: y] depends;
Product-valued assignments
a1 pair_of = [left: b1, right: c1];
ot output_terminal/src = [firing: f1, arc: SimpleNet/arc_out];
Nested instance literals
Instance-valued fields can be assigned inline blocks.
initial_marking = {
tok : token;
tok token/of = ExampleNet/A;
};
= { ... } vs = chase { ... }
The examples consistently use two instance forms.
Plain instance
instance Triangle : Graph = {
...
}
This gives a direct structure with only the explicitly listed elements and assignments.
Chase instance
instance Chain : Graph = chase {
...
}
This marks an instance whose contents should be extended by the theory axioms. Examples use this for transitive closure, existential witness generation, and trace/reachability constructions.
Observed Design Patterns
Parameterized theories
Theories can be abstract over:
- a sort, such as
theory (X : Sort) Container - an instance, such as
theory (N : PetriNet instance) Marking - multiple arguments, such as
theory (N : PetriNet instance) (RP : N ReachabilityProblem instance) Solution
Theory application by adjacency
Theory arguments are written before the theory name.
N Marking instance
MyBase Map
ExampleNet problem0 Solution
Nested structure via qualified names
Many examples model dependent structure by naming into earlier declarations.
token/of : token -> N/P;
initial_iso : (trace/input_terminal) (RP/initial_marking/token) Iso instance;
What Seems Outside the File DSL
Some example comments refer to interactive commands such as:
:source
:load
:inspect
:chase
:solve
Those commands appear to belong to an external REPL or tool environment rather
than to the .geolog file grammar itself.
Querying
The examples do not show a stable, implemented query form inside .geolog
files in the same way they show theory and instance declarations.
What they do show is:
1. External interactive commands
Some files suggest that querying or inspection happens through an external tool or REPL:
:source examples/geolog/transitive_closure.geolog
:inspect Chain
:chase Chain
:solve EmptyModel
Based on the example comments, these commands appear to mean roughly:
:sourceor:load: load Geolog definitions from files:inspect: inspect a declared instance:chase: materialize or display the closure of a= chaseinstance:solve: ask a solver to construct a satisfying instance for a theory
These are tool commands, not part of the confirmed .geolog declaration syntax.
2. A sketched future query form
One file contains a commented-out example of a possible query block:
query can_reach_B_from_A {
? : ExampleNet problem0 Solution instance;
}
This suggests an aspirational style where querying is expressed as asking for a witness inhabiting some instance type. However, in the current examples this is only a comment, not an observed live construct.
3. Current implemented querying elsewhere in the repo
The currently implemented query syntax in this repository belongs to the minimal frontend language, not to Geolog. That language supports forms such as:
query Ancestor(?X, ?Y)?
explain Ancestor(alice, carol)?
So the safest summary is:
- Geolog examples define theories, instances, and chase-oriented structure.
- Querying appears to be external, REPL-driven, or still in design.
- The only clearly implemented query syntax in this repo today is the minimal
.echfrontend query language.
Best Example Files by Feature
transitive_closure.geolog: basic theory, axiom, and= chaseusagegraph.geolog: plain structural instancesmonoid.geolog: postfix application and positional record syntaxtodo_list.geolog: unary predicates and disjunctionsort_param_simple.geolog: sort and instance parametersnested_instance_test.geolog: nested instance-valued fieldsproduct_codomain_test.geolog: record-valued function codomainsfield_projection_test.geolog: field projection syntaxrecord_existential_test.geolog: existential witness creation with recordspetri_net_showcase.geolog: large multi-theory compositionsolver_demo.geolog: satisfiability-oriented axiom patterns
Minimal Example
theory Graph {
V : Sort;
Edge : [src: V, tgt: V] -> Prop;
Path : [src: V, tgt: V] -> Prop;
ax/base : forall x, y : V.
[src: x, tgt: y] Edge |- [src: x, tgt: y] Path;
}
instance Chain : Graph = chase {
a : V;
b : V;
[src: a, tgt: b] Edge;
}
That small example already shows the core structure of the DSL:
- a
theory - sort and predicate declarations
- an axiom written as a sequent
- an
instance - a
chaseblock that asks for closure under the theory axioms