Clausal¶
Beta
Clausal is in early beta. The API, syntax, and module interfaces are all subject to 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 brings Prolog-style logic programming to Python — not as a front-end to an external engine, but as a genuine part of the Python runtime. Python code and logic code call into each other freely, share the same objects, and run on the same VM, and the same garbage collector. No boilerplate, no latency, no memory leaks, no friction.
# fibonacci.clausal
-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
)
from clausal import Var
from fibonacci import fib
for trail in fib(10, F := Var()):
print(F.value) # 55
Why Clausal?¶
- Python syntax and semantics — Clausal code uses Python's parser. No separate parser, no foreign operators to learn.
- Deep integration — predicates are Python classes, logic variables are Python objects, backtracking uses Python generators.
- 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¶
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 |
| Predicates | How to define predicates in .clausal files |
| 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 | .clausal file loading, module directives, qualified calls |
| Importing Prolog | Import .pl files directly — on-the-fly translation and caching |
| Architecture | Layer stack, execution model, why not a WAM |
| Python Integration | Query API, ++() escape, Python interop |
| Reflection | Reify .clausal source as matchable terms — linters and matchers in Clausal |
| IPython / Jupyter REPL | Interactive queries, *(goals) syntax, solution browsing |
| Standard Library Modules | |
| Physical Units | n(Unit) sugar, dimensional arithmetic, AttVar constraints |
| 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 clausal ↔ 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 Clausal predicates |
| Parallel Queries | Running parallel queries from Python |