Clausal Prolog¶
Beta
Clausal Prolog is in beta on the way to 1.0. From 1.0.0, the surface listed in Public API follows semantic versioning; everything else may still change. The developer experience has not been widely tested beyond the author's own use. Expect rough edges — bug reports and feedback are very welcome.
Logic programming embedded in Python.
Clausal Prolog is a cut-free Prolog, aiming for ISO Prolog conformity, that runs inside the Python runtime. It is not a front end to an external engine. Logic code and Python code call into each other, share the same objects, and run on the same VM and garbage collector.
% fibonacci.clausal
:- module(fibonacci, [fib/2]).
:- use_module(library(clpz)).
:- table(fib/2).
fib(0, 0).
fib(1, 1).
fib(N, F) :-
N #> 1,
N1 #= N - 1, N2 #= N - 2,
fib(N1, F1), fib(N2, F2),
F #= F1 + F2.
test("fib(10) = 55") :- fib(10, 55).
:- end_module(fibonacci).
Ask it a question from a .seam file, with the goal after --:
From a plain .py file, the same query goes through solve:
from clausal import Var, solve
import fibonacci # loads fibonacci.clausal
for trail in solve(("fib", 10, F := Var()), module=fibonacci):
print(F.value) # 55
Answers come back as the engine's own terms, which are plain Python values:
an atom is a str, a compound term is a tuple ('point', 1, 2), a string is
the carrier ('$chars', 'text'). See Python Integration.
Three source surfaces¶
| Extension | Surface | Use it for |
|---|---|---|
.clausal |
Clausal Prolog: ISO syntax, cut-free | Your logic programs |
.pl |
ISO Prolog (experimental) | Existing Prolog code |
.seam |
The seam: Python syntax | The boundary with Python: ++expr, hosted Python, adapters |
Many language pages in these docs still show their examples in seam syntax. Each one says so, and the semantics carry over to Clausal Prolog. Clausal Prolog gives the spelling differences and the rules the surface enforces.
Why Clausal Prolog?¶
- Heading for ISO Prolog — ISO syntax, ISO builtin names and ISO error terms; where ISO is silent, Clausal Prolog follows Scryer Prolog. See Operators and Public API.
- Pure by design — no cut and no committed choice:
dif/2, reified if-then-else, constraints and tabling keep programs monotonic. See Purity. - Deep integration — terms are Python tuples and atoms are Python strings, backtracking uses Python generators, and Python libraries are reached through
library(...)facades and.seammodules. - Full-featured — tabling, CLP(ℤ), DCGs, EDCGs, modules, term expansion, goal expansion, reified if-then-else.
- Fast — C extension for unification/trails, first-argument indexing, groundness-keyed dispatch, tail recursion optimization, bytecode caching.
Interactive example — Sudoku in IPython¶
The IPython integration uses seam syntax, since it runs inside Python.
Start IPython with the integration enabled:
Then solve a Sudoku puzzle interactively:
In [1]: from clausal.examples.sudoku import *
In [2]: *(ROWS is [
...: [1, _, _, 8, _, 4, _, _, _],
...: [_, 2, _, _, _, _, 4, 5, 6],
...: [_, _, 3, 2, _, 5, _, _, _],
...: [_, _, _, 4, _, _, 8, _, 5],
...: [7, 8, 9, _, 5, _, _, _, _],
...: [_, _, _, _, _, 6, 2, _, 3],
...: [8, _, 1, _, _, _, 7, _, _],
...: [_, _, _, 1, 2, 3, _, 8, _],
...: [2, _, 5, _, _, _, _, _, 9],
...: ], solve(ROWS))
Out[2]: ROWS is [
[1, 5, 6, 8, 9, 4, 3, 2, 7],
[9, 2, 8, 7, 3, 1, 4, 5, 6],
[4, 7, 3, 2, 6, 5, 9, 1, 8],
[3, 6, 2, 4, 1, 7, 8, 9, 5],
[7, 8, 9, 3, 5, 2, 6, 4, 1],
[5, 1, 4, 9, 8, 6, 2, 7, 3],
[8, 3, 1, 5, 4, 9, 7, 6, 2],
[6, 9, 7, 1, 2, 3, 5, 8, 4],
[2, 4, 5, 6, 7, 8, 1, 3, 9]
]
# No more solutions.
Uppercase names (ROWS) are automatically allocated as logic variables. The
*(...) form is the IPython query syntax — see IPython / Jupyter REPL
for the full feature set.
What's inside¶
| Section | What you'll find |
|---|---|
| Foundations | |
| Thinking Relationally | The most important idea: predicates as relations, not functions |
| Purity and Monotonicity | Why pure code has better properties and how to write it |
| Start Here | |
| For Python Programmers | Bridge from functions and loops to relations and search |
| For Prolog Programmers | Syntax mapping, what's the same, what's different |
| For AI Agents | Why LLMs should generate logic programs |
| For Decision Makers | The business case: explainability, reliability, rules-as-code |
| Getting Started | |
| Syntax | The trailing-comma convention, escape operators, logic variables, clause syntax |
| Style & Formatting | One goal per line, clause separation, clausal-fmt |
| Clausal Prolog | The .clausal surface: ISO syntax, cut-free, its rules and how it differs from the seam |
| Predicates | How to define predicates |
| Builtins | Complete index of built-in predicates |
| Dicts & Sets | DictTerm, SetTerm, __unify__ protocol |
| Constraints | dif/2, CLP(ℤ) integer constraints, and CLP(ℝ) real-domain constraints |
| CLP(ℝ) | Interval arithmetic, non-linear propagation, and bisection labeling over the reals |
| CLP(Q) | Exact rational constraints via Gaussian elimination and the revised simplex method |
| Tabling | SLG resolution and well-founded semantics |
| Lambdas | Goal closures for higher-order logic programming |
| If-Then-Else | Reified branching (no cut, no committed choice) |
| Import System | Module loading, module directives, qualified calls |
| Importing Prolog | Import .pl files directly — on-the-fly translation and caching (experimental in 1.0) |
| Architecture | Layer stack, execution model, why not a WAM |
| Python Integration | Querying with --goal, the ++() escape, solve(), converters |
| Operators | What each operator means bare (Python) and quoted (Scryer/ISO) |
| Arithmetic | Evaluation, exact rationals, the evaluable functors |
| Public API | What the 1.0 semantic-versioning promise covers |
| Reflection | Reify .seam source as matchable terms — linters and matchers written as logic programs |
| IPython / Jupyter REPL | Interactive queries, *(goals) syntax, solution browsing |
| Standard Library Modules | |
| Physical Units | n(Unit) sugar, dimensional arithmetic, AttVar constraints |
| Currency | Exact-decimal money as units base dimensions; rounding/display; precision checks |
| Regex | Pattern matching, group extraction, auto-binding |
| Symbolic Math | SymPy integration — calculus, algebra, number theory |
| YAML | YAML parsing and generation |
| Date/Time | Date, time, and datetime predicates |
| Logging | Structured logging predicates |
| UUID | UUID generation and inspection |
| Graphs | Graph traversal, pathfinding, connectivity, MST |
| Random | Random number generation, selection, seeding |
| JSON | JSON parsing, generation, DictTerm integration |
| CSV | CSV parsing, generation, DictTerm records |
| OS | Environment variables, working directory, process info, platform |
| Files | File/directory existence, listing, metadata, CRUD, path manipulation |
| Process | Shell commands, subprocess execution, sleep |
| SQLite | SQLite database predicates |
| spaCy NLP | NLP pipeline — tokenisation, NER, POS, similarity |
| scipy.special | Special mathematical functions — gamma, Bessel, elliptic, hypergeometric, orthogonal polynomials |
| scipy.linalg | Linear algebra — solvers, decompositions, matrix functions, factorisations |
| scipy.optimize | Optimisation — minimisation, root finding, curve fitting, linear programming |
| scipy.integrate | Numerical integration — quadrature, ODE solvers, sampled-data methods |
| scipy.interpolate | Interpolation — splines, PCHIP, Akima, regular grids, radial basis functions |
| scipy.stats | statistics — descriptive stats, hypothesis tests, distributions |
| scipy.fft | Discrete Fourier transforms — FFT, inverse FFT, helper functions |
| scipy.ndimage | N-dimensional image processing — filters, morphology, transforms, measurements |
| scipy.spatial | Spatial algorithms — distance functions, KD-tree, ConvexHull, Delaunay, Rotation |
| Crypto | Cryptographic hashing, HMAC signing, PBKDF2 key derivation |
| HTTP & URL | HTTP requests (GET, POST, JSON), URL encoding and parsing |
| TCP | TCP client/server sockets — connect, listen, send, receive |
| Testing | Writing test predicates, running the test suite |
| DCGs | Definite Clause Grammars for parsing |
| Exceptions | throw/catch, structured error terms |
| Coroutining | freeze/2, when/2, setup_call_cleanup/3, call_nth/2, count_all/2 |
| CLP(B) | Boolean constraint programming |
| Z3 SMT Solver | Multi-theory constraints via Z3 — integers, reals, booleans, bitvectors, arrays, strings, optimization, unsat cores |
| Meta-Interpreter Specialization | Partial deduction — specialize MIs to remove interpretation overhead |
| Prolog Translation | Bidirectional seam ↔ Prolog translation |
| Trealla Prolog Embedding | In-process Trealla Prolog engine via ctypes — fast, lightweight, instant startup |
| Scryer Prolog Embedding | In-process Scryer Prolog engine via PyO3 — lazy queries, tabling support |
| Examples | Example programs: Fibonacci, N-Queens, Sudoku, meta-interpreters |
| Scientific Computing | |
| scikit-learn | Machine learning: estimators, pipelines, cross-validation |
| scipy.cluster | Hierarchical clustering, k-means, vector quantisation |
| scipy.constants | CODATA physical constants, SI prefixes |
| scipy.differentiate | Numerical differentiation: Derivative, Jacobian, Hessian |
| scipy.signal | Signal processing: filter design, filtering, spectral analysis |
| scipy.sparse | Sparse matrices and sparse linear algebra |
| Infrastructure | |
| Compiler | Compilation pipeline: head patterns, body goals, trampoline, TRO |
| Jupyter Notebooks | Notebook integration with HTML rendering |
| Free Threading | Free-threaded Python (PEP 703) support, C extension safety |
| Parallel Predicates | Writing thread-safe predicates |
| Parallel Queries | Running parallel queries from Python |