A Prolog transpiler that turns logic programs into LINQ-style data pipelines.
One codebase → Bash streams, C# queries, Go binaries, SQL views, and more.
📚 Extended Documentation | 🎓 Educational Materials
Write your data relationships and queries once in Prolog, then compile to the target that fits your environment:
- Shell scripts for Unix pipelines and automation
- Native binaries for portable, dependency-free deployment
- SQL views for database integration
- .NET assemblies for enterprise applications
- Multi-language pipelines via cross-target glue
UnifyWeaver handles the hard parts—recursion, transitive closures, cycle detection, deduplication—so your generated code is correct and efficient.
UnifyWeaver supports multiple compilation strategies depending on the target and predicate complexity:
| Approach | Description | Targets |
|---|---|---|
| Stream/Procedural | Direct template-based code generation with Unix pipes or LINQ iterators | Bash, Go, Rust, C# Stream, PowerShell |
| Fixed-Point (Query Engine) | IR + runtime with semi-naive evaluation for complex recursion | C# Query Runtime |
| Generator-Based | Lazy evaluation via Python generators with memoization | Python |
| Declarative Output | SQL queries for external database execution | SQL |
| Symbolic WAM | Low-level abstract machine instructions for complex unification/backtracking | WAM (Hub) |
| WAM Transpilation | WAM instructions compiled to target-language WAM virtual machine implementations | C, Rust, Go, LLVM, JVM, ILAsm, Elixir |
Several targets support a hybrid WAM compilation path: Prolog is first compiled to WAM (Warren Abstract Machine) instructions, then those instructions are transpiled into a complete WAM virtual machine implementation in the target language. This provides full unification and backtracking semantics.
| Target | WAM Module | Format | State Representation | Run Loop |
|---|---|---|---|---|
| C | wam_c_target |
Single | Structs + tagged unions, manual memory | while loop |
| Rust | wam_rust_target |
Single | HashMap/Vec, enum WamValue |
loop + match |
| Go | wam_go_target |
Single | map[string]interface{}, slices |
for loop + switch |
| LLVM | wam_llvm_target |
Single | SSA registers, stack alloca | Basic blocks + br |
| JVM | wam_jvm_target |
Dual (Jamaica / Krakatau) | HashMap/ArrayList fields |
while + tableswitch |
| ILAsm (.NET) | wam_ilasm_target |
Single | Dictionary/List fields |
br loop + switch |
| Elixir | wam_elixir_target |
Single | %WamState{} struct, immutable maps |
Recursive run/1 |
Each WAM target includes:
- 26 instruction arms covering head unification, body construction, control flow, and choice points
- Helper functions: run loop, backtrack, trail unwinding, unification, builtin dispatch
- Full project generation: source files, headers/configs, and build files
- Dedicated test suite validating instruction coverage, code idioms, and runtime assembly
Different targets support different recursion patterns. Choose based on your needs:
| Pattern | Bash | C# Query | Go | Rust | Python | SQL | PowerShell | AWK | Prolog |
|---|---|---|---|---|---|---|---|---|---|
| Linear Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ |
| Tail Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ |
| Tree Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ |
| Transitive Closure | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ |
| Mutual Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ |
| Aggregations | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Advanced Aggregations | — | — | ✅ | — | — | ✅ | — | — | ✅ |
Aggregations = dynamic fold expression extraction for list/numeric linear recursion (e.g., extracting
*fromF is N * F1). Advanced Aggregations = fullaggregate_all/3support with grouping, having filters, and multiple aggregation operations (sum, count, max, min, avg).
Targets for functional / FP-oriented languages with pattern matching and immutability:
| Pattern | Haskell | F# | Scala | Clojure | Elixir |
|---|---|---|---|---|---|
| Linear Recursion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Tail Recursion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Tree Recursion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Transitive Closure | ✅ | ✅ | ✅ | ✅ | ✅ |
| Mutual Recursion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Aggregations | ✅ | ✅ | ✅ | ✅ | ✅ |
| Pattern | Java | Kotlin | Scala | Clojure | Jython |
|---|---|---|---|---|---|
| Linear Recursion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Tail Recursion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Tree Recursion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Transitive Closure | ✅ | ✅ | ✅ | ✅ | ✅ |
| Mutual Recursion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Aggregations | ✅ | ✅ | ✅ | ✅ | ✅ |
Scala and Clojure also appear in the Functional table above.
| Pattern | WASM | TypeScript | VB.NET |
|---|---|---|---|
| Linear Recursion | ✅ | ✅ | ✅ |
| Tail Recursion | ✅ | ✅ | ✅ |
| Tree Recursion | ✅ | ✅ | ✅ |
| Transitive Closure | ✅ | ✅ | ✅ |
| Mutual Recursion | ✅ | ✅ | ✅ |
| Aggregations | ✅ | ✅ | ✅ |
| Pattern | C | C++ | Ruby | Perl | Lua | R |
|---|---|---|---|---|---|---|
| Linear Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Tail Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Tree Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Transitive Closure | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Mutual Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Aggregations | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Low-level assembly and intermediate representation targets:
| Pattern | Jamaica (JVM) | Krakatau (JVM) | ILAsm (.NET) | WAT (WASM) | LLVM IR | WAM |
|---|---|---|---|---|---|---|
| Linear Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Tail Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Tree Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Transitive Closure | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Mutual Recursion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Aggregations | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Pattern | Flutter | React Native | SwiftUI | Vue |
|---|---|---|---|---|
| Linear Recursion | ✅ | ✅ | ✅ | ✅ |
| Tail Recursion | ✅ | ✅ | ✅ | ✅ |
| Tree Recursion | ✅ | ✅ | ✅ | ✅ |
| Transitive Closure | ✅ | ✅ | ✅ | ✅ |
| Mutual Recursion | ✅ | ✅ | ✅ | ✅ |
| Aggregations | ✅ | ✅ | ✅ | ✅ |
All Python variants share the core python_target recursion support and add specialized compilation:
| Variant | Runtime | Specialty | Standalone Binary |
|---|---|---|---|
| CPython | CPython 3.x | Full-featured, generators, streaming JSONL | — |
| Jython | JVM | Java interop, JVM libraries | — |
| IronPython | .NET/CLR | C# interop, in-process .NET hosting | — |
| Cython | C extension | cdef typed functions, C-speed inner loops |
— |
| MypyC | Compiled | Strict type annotations → native extensions | — |
| Numba | LLVM JIT | @jit/@njit decorators, vectorized, parallel |
— |
| Codon | LLVM AOT | Static subset of Python, @par parallel loops |
✅ |
| Nuitka | C compiled | Full Python → standalone executable, webapp mode | ✅ |
| Pyodide | WASM | Browser-side Python via WebAssembly, packages([numpy]) |
— |
| Fuzzy | CPython | Fuzzy string matching, semantic search integration | — |
Key:
- ✅ Full support with optimizations (BFS, loops, memoization, semi-naive)
- — Not supported or limited
| If you need... | Use |
|---|---|
| Shell scripts for Unix pipelines | Bash |
| Standalone binary, no runtime deps | Go, Rust, or C |
| Complex recursion in .NET apps | C# Query Runtime |
| Database views and analytics | SQL |
| Python ecosystem integration | Python |
| Windows/.NET orchestration | PowerShell |
| BEAM VM with OTP concurrency | Elixir |
| Lightweight text processing | AWK |
| Prolog dialect transpilation | Prolog |
| JVM bytecode (assembler-level) | Jamaica or Krakatau |
| .NET IL bytecode | ILAsm |
| WebAssembly (text format) | WAT |
| LLVM IR for custom backends | LLVM |
| Full WAM unification/backtracking | Any WAM hybrid target |
UnifyWeaver supports optional predicate type metadata through Prolog facts.
Argument types:
uw_type(edge/2, 1, atom).
uw_type(edge/2, 2, atom).Return types:
uw_return_type(lower_name/2, atom).Typed targets such as typr consume this metadata directly.
The plain r target does not require type metadata, but if
uw_return_type/2 is present it will use it by default for:
- better fallback/result-shape generation
- simple compile-time compatibility checks
This behavior can be disabled per compile call:
compile_predicate_to_r(lower_name/2, [type_constraints(false)], Code).Optional diagnostics are also available:
compile_predicate_to_r(lower_name/2, [type_diagnostics(warn)], Code).
compile_predicate_to_r(lower_name/2, [type_diagnostics(error)], Code).off(default): silent fallback/filteringwarn: emit a warning and continueerror: throw on a type-constraint violation
Structured diagnostics can also be collected without warning or throwing:
compile_predicate_to_r(lower_name/2, [type_diagnostics_report(Report)], Code).Report is bound to a list of dicts with keys such as:
targetpredicateactionexpectedinferredbody
TypR now uses the same shared return-type metadata and conservative inference layer. For simple binding-shaped predicates and literal-guarded multi-clause branches it lowers directly to native TypR syntax. That native subset now includes:
- simple output-producing binding chains
- simple alias or arithmetic assignment tails after an earlier native string-transform or length-producing step
- simple alias tails after native conversion, list, and path producers such as
to_numeric/2,reverse/2,dirname/2,atom_string/2, narrowedsub_atom/5,string_substr/4, and representative extra-parameter string producers such asstring_replace/4,string_sub/4,string_format/3, andstring_grepl/3 - guard-style command predicates such as
is_character/1 - unary TypR-safe I/O commands such as
cat/1andprint/1, emitted as native fixed-arity TypR calls - multi-argument output should still be composed explicitly, e.g.
cat(paste("x =", x)) - multi-step native control-flow chains where an earlier output feeds a later guard and output
- simple comparison and boolean guard expressions over already-bound intermediates
- structured fan-out chains where one earlier bound value feeds multiple later derived outputs or conditions
- structured split-and-recombine chains where guarded derived values are later combined into a final native output
- guarded disjunction-style alternative-assignment chains where each native alternative may introduce different branch-local intermediates before binding either the same later intermediate or the final output directly, and later native steps continue from the selected result
- guarded disjunction-style multi-result chains where each native alternative may introduce different branch-local intermediates before binding the same later variables, and later native steps continue from those selected results
- multiple sequential branch/rejoin segments in the same native body, including multi-result rejoin chains that continue through later native steps after each rejoin
- asymmetric partial-rejoin chains where alternatives first converge on only part of the later state, subsequent native steps derive additional shared values, and a later rejoin still stays native
- Prolog
if -> then ; elsechains where the branches bind either the same later intermediate, the final output directly, the same later result set, or guard-only control flow before later native steps continue from the selected values, including cases where one branch introduces additional branch-local intermediates before producing that shared later result set - Prolog
if -> thenchains where thethenbranch either contributes guard-only control flow for later native steps or binds a later intermediate, the final output directly, or the later result set needed by subsequent native steps - transitive-closure generation where BFS control flow, seeded adjacency
storage, vector-parameter runtime query helpers, explicit
input(stdin|file|vfs|function)loader wrappers, and declared scalar or conservative pair-shaped runtime node parsing all stay in native TypR syntax - conservative per-path visited recursion like
category_ancestor/4, moved-input variants, andcategory_ancestor_weight/5, where a compile-time- seeded step relation and detectedVisitedposition lower to a native TypR recursive worker that returns nested pair results with one direct node output and one or more additive numeric outputs; this path now supports one recursion-driving input plus conservative invariant non-visited inputs, including one helper/guard segment between the step relation and recursive call, and it also emits a native*_from_vectorsruntime helper, nativeinput(stdin|file|vfs|function)wrappers, and declared scalar or conservative pair-shaped runtime node parsing such asinteger,number,pair(integer, integer), andpair(number, number)over the same step-relation shape; the first conservative path-aware aggregation slice also now stays native foraggregate_all(count, per_path_goal, N)wrappers over that supported per-path worker path - accumulator-style tail-recursive predicates such as
factorial_acc/3, lowered to TypR functions that use native TypR loop bodies instead of relabeled standalone R scripts - conservative single-recursive-call numeric linear-recursive predicates with
one recursion-driving argument and invariant context args, such as
factorial_linear/2andpower/3, lowered to TypR functions that use native TypR fold/loop bodies instead of wrapped-R fallback - conservative single-recursive-call list linear-recursive predicates with
one recursion-driving list argument and invariant context args, such as
list_length/2andlist_length_from/3, lowered to TypR functions that use native TypR fold/loop bodies instead of wrapped-R fallback - conservative arity-2 numeric multi-call tree-recursive predicates such as
fib/2, lowered to TypR functions that use native TypR memoized helper bodies instead of wrapped-R fallback - conservative boolean mutual-recursive predicate groups such as
is_even/1/is_odd/1,even_list/1/odd_list/1,even_left_tree/1/odd_left_tree/1, andeven_tree/1/odd_tree/1, plus conservativeN-ary tree-structural SCCs with one tree-driving argument and one or more threaded context arguments, including dual-subtree tree SCCs with alias-style prework, shared computed context updates, or guarded shared context selection before the two recursive subtree calls, or direct recursive subtree calls inside supported guarded branch bodies with one nested branch-local control point around those calls and limited branch-local alias or guard state around those calls, including one nested branch-local control point around those calls before the shared boolean rejoin, one nested branch-local control point between the two direct recursive subtree calls with limited alias or guard state, one nested post-call control point after the shared dual-subtree calls before the shared boolean rejoin, inter-call symbolic context or alias state before the second call combined with that shared post-call control, nested non-recursive boolean post-call control after the shared dual-subtree calls, shared branch-local guard prework before a nested mutual branch, and the same conservative guarded branch-body family with one invariant context argument threaded through the subtree calls, including branch bodies where one shared subtree call happens before guarded control that contains the second subtree call plus nested non-recursive post-call control, shared context updates before that first subtree call, or branch-local context updates before the second subtree call, plus conservative integer-return tree-structural SCCs with one-subtree or shared dual-subtree descent, guarded branch-local alias selection before those shared subtree calls or direct recursive subtree calls inside supported guarded branch bodies, and simple post-call arithmetic recombination, including branch-local post-call arithmetic steps inside those supported guarded branch bodies, overvalue,left_result,right_result, and any threaded context args, including mixed-shape SCCs where different predicates in the same group use different supported one-subtree, shared-call, or guarded branch-body forms, and mixed tree/list structural SCCs where tree-shaped predicates recurse through paired-forest helpers, including guarded branch-local paired-forest call selection on the tree side, while list-shaped predicates recurse through head/tail decomposition or fixed two-element forest-pair decomposition or fixed pair-tail forest decomposition like[A, B|Ts], plus mixed list/numeric SCCs where list-shaped predicates recurse through head/tail or pair-tail decomposition like[A, B|Ts]while numeric predicates recurse through scalar step descent, singleton-list re-entry, or fixed pair-list re-entry, plus mixed tree/numeric SCCs where tree-shaped predicates recurse through current-value and one- subtree descent while numeric predicates recurse through scalar step descent or constructed tree re-entry, plus mixed tree/list/numeric SCCs where tree-shaped predicates recurse through current-value and paired- forest helpers while list-shaped predicates recurse through head/tail decomposition and numeric predicates recurse through scalar step descent or constructed tree re-entry, including mixed tree/numeric and mixed tree/list/numeric SCCs where the tree-shaped predicate uses the same supported guarded full-body forms after an earlier recursive group- call prefix, plus integer-return and threaded-context variants, lowered to TypR functions that use native TypR helper bodies instead of wrapped-R fallback - the first SCC IR-backed helper-goal slice is now in place:
mixed tree/numeric SCCs with a local nonrecursive helper goal between
recursive group calls now stay native in TypR instead of falling out with
No mutual recursion support for target typr - the next confirmed SCC gap is broader than another structural micro-slice: broader helper-goal nodes and richer branch/result structure still point to a shared SCC IR as the next compiler step rather than more matcher families
- conservative
N-ary structural tree-recursive predicates with one tree-driving argument and invariant context args, such astree_sum/2,tree_height/2,weighted_tree_sum/3,weighted_tree_affine_sum/4,weighted_tree_sum_scale_step/3,weighted_tree_sum_scale_branch/3,tree_sum_branch_calls/2,weighted_tree_branch_calls/3,tree_sum_recursive_branch/2,weighted_tree_recursive_branch/3,tree_sum_nested_recursive_branch/2,weighted_tree_nested_recursive_branch/3,tree_sum_nested_branch_recombine/2,weighted_tree_nested_branch_recombine/3,tree_sum_nested_branch_prework/2,weighted_tree_nested_branch_prework/3,tree_sum_double_nested_calls/2,weighted_tree_double_nested_calls/3,weighted_tree_sum_subtree_scale/3,weighted_tree_sum_subtree_branch/3,tree_sum_prework/2,weighted_tree_sum_prework/3,tree_sum_branch/2,weighted_tree_sum_branch/3,tree_sum_asym_branch/2, andweighted_tree_sum_asym_branch/3, lowered to TypR functions that use native TypR structural helper bodies over[]/[V, L, R]trees, including limited native guards, localissteps, threaded invariant-context updates before the two subtree calls, per-subtree invariant-context updates for the left and right recursive calls, nested branch-local subtree-context selection before shared recursive subtree calls, branch-local recursive-call aliases before the two subtree calls, guarded pre-recursive branching before the two subtree calls, recursive subtree calls inside supported branch bodies, nested recursive subtree calls inside supported branch bodies, shared pre-recursive local work before nested recursive branch bodies, nested branch-local post-recursive recombination before a later shared result expression, multiple nested branch-local control points around the two subtree calls, and asymmetric branch-local prework that is reconciled later by a guarded result expression, instead of wrapped-R fallback - guarded post-recursive recombination in those same linear-recursive
shapes, including multi-state branch-local recombination such as
power_if/3,count_occ/3,power_multistate/3, andcount_weighted/3, where the recursive result and later selected intermediate values are recombined through native TypRifexpressions instead of wrapped-R fallback - asymmetric post-recursive recombination in those same linear-recursive
shapes, such as
asym_rec_a/3andasym_rec_c/3, where different branch-local intermediates feed a shared later result expression and still stay native in TypR - two-level nested guarded alternatives inside supported semicolon branches, including nested multi-result selections, where each nested branch still selects the same later result set natively
- supported literal-headed branch bodies built from those chains, with
letused for new intermediate TypR locals - dataframe helpers such as
filter/3,sort_by/3, andgroup_by/3
More complex generic bodies still fall back to the wrapped R path.
The wrapped fallback boundary is now beyond the first native
string-transform/output-tail slice; if this area is extended further, the next
real audit target is the producer-goal family after the currently supported
string_lower/2, string_upper/2, string_length/2, to_numeric/2,
reverse/2, dirname/2, atom_string/2, broader constant-parameter
substring slices such as sub_atom/5 and string_substr/4, and
representative extra-parameter string producers such as string_replace/4,
string_sub/4, string_format/3, and string_grepl/3 follow-on alias or
arithmetic tails, and the first list-producing Prolog string helper slice
split_string/4 with a constant separator and empty pad chars followed by a
simple alias tail.
TypR annotation modes are regression-covered too:
typed_mode(explicit)emits available annotationstyped_mode(infer)keeps the current minimal scalar-annotation behaviortyped_mode(off)emits untyped function signatures- per-predicate
uw_typed_mode/2overrides per-call mode options - current CLI validation boundary:
inferandoffare covered withtypr check; the currenttypr buildpath still expects typed function signatures more often than the checker does - per-path unique-path work also has a dedicated TypR design note: docs/design/TYPR_PER_PATH_UNIQUE_PATH_DESIGN.md which now records the first counted aggregation slice as landed and points next toward grouped or min-style path-aware aggregation
Worked example:
Stream-based compilation to Unix shell scripts with pipes and process substitution.
- BFS optimization for transitive closures
- Cycle detection and duplicate prevention
- Template-based code generation
- Enhanced Chaining — Fan-out, merge, conditional routing, and filtering stages
Docs: Enhanced Chaining
Standalone native binaries with no runtime dependencies.
- JSON I/O with schemas and nested path extraction
- Regex matching with capture groups
- Embedded bbolt database storage
- Parallel workers for high-throughput processing
- Enhanced Chaining — Fan-out, merge, conditional routing, and filtering stages
- Binding System — Map predicates to Go stdlib functions
Docs: Go Target Guide | Enhanced Chaining
Memory-safe native binaries via Cargo.
- Serde JSON integration
- Semantic crawling support
- Full Cargo project scaffolding
- Enhanced Chaining — Fan-out, merge, conditional routing, and filtering stages
- Binding System — Map predicates to Rust stdlib and crates
Two compilation modes for different needs:
- Stream Target (
csharp_codegen) — LINQ pipelines for simple predicates - Query Runtime (
csharp_query) — IR + semi-naive fixpoint for complex recursion
Features: LiteDB integration, mutual recursion via SCC, arithmetic constraints.
- Enhanced Chaining — Fan-out, merge, conditional routing, and filtering stages
- Binding System — Map predicates to .NET APIs and LINQ
Docs: C# Compilation Guide | Enhanced Chaining
Generator-based streaming with Python ecosystem integration and multi-runtime support.
- Pipeline Mode — Streaming JSONL I/O with typed object output
- Runtime Selection — Auto-select CPython, IronPython, PyPy, or Jython based on context
- Pipeline Chaining — Connect multiple predicates with
yield fromcomposition - Enhanced Chaining — Fan-out, merge, conditional routing, and filtering stages
- Cross-Runtime Pipelines — Stage-based orchestration for mixed Python/C# workflows
- C# Hosting — IronPython in-process or CPython subprocess with JSONL glue
- Binding System — Map predicates to Python built-ins and libraries
- Native XML via lxml, semantic runtime with SQLite and vector search
Docs: Python Target Guide | Enhanced Chaining
Compiles predicates to SQL queries for database execution.
- Recursive CTEs for hierarchical data
- Window functions (RANK, ROW_NUMBER, LAG, LEAD)
- All JOIN types, aggregations, subqueries
- Works with SQLite, PostgreSQL, MySQL, SQL Server
Docs: SQL Target Design
Windows automation and .NET orchestration with full object pipeline support.
- Dual-mode: pure PowerShell or Bash-as-a-Service via WSL
- Cross-platform (PowerShell 7+)
- Binding system: 68+ bindings for cmdlets, .NET methods, Windows automation
- Auto-transpilation: Rules like
sqrt(X, Y)compile directly to[Math]::Sqrt($X) - Enhanced Chaining — Fan-out, merge, conditional routing, and filtering stages
- Object pipeline:
ValueFromPipelineparameters,PSCustomObjectoutput - Advanced joins: Hash-based and pipelined N-way joins with O(n+m) complexity
- Firewall security: Per-predicate mode control (pure/baas/auto)
- Ideal for orchestrating .NET targets (C#, IronPython)
Docs: PowerShell Target Guide | Enhanced Chaining
Lightweight, portable text processing.
- Tail recursion to while loops
- Aggregations (sum, count, max, min, avg)
- Regex matching with capture groups
- Enhanced Chaining — Fan-out, merge, conditional routing, and filtering stages
- Runs on any POSIX system
Docs: Enhanced Chaining
Prolog-to-Prolog transpilation for dialect compatibility.
- SWI-Prolog and GNU Prolog support
- Native binary compilation via gplc
- Executable script generation
BEAM VM compilation with native pattern matching and tail-call optimization.
- Multi-clause
defwith pattern-matched function heads snake_to_camel/2for idiomatic CamelCase module names- Pipeline mode with
Stream+ Jason JSONL processing - Generator mode via
Stream.unfold/2 - Transitive closure via BFS with
Map+MapSet - Binding System — Arithmetic, comparison, string, I/O mappings
Docs: Elixir Target Guide
Compose predicates across multiple languages in unified pipelines:
- Shell Integration — TSV/CSV/JSON I/O between AWK, Python, Bash
- .NET Bridges — In-process C# ↔ PowerShell ↔ IronPython
- Python/C# Glue — IronPython in-process hosting or CPython subprocess with JSONL
- Pipeline Chaining — Multi-stage orchestration with automatic runtime grouping
- Native Orchestration — Go/Rust compilation with parallel workers
- Network Communication — HTTP servers/clients, TCP streaming
- Service Registry — Distributed service routing
Docs: Cross-Target Glue Guide
Built-in data source plugins for real-world pipelines:
| Source | Description |
|---|---|
| CSV/TSV | Auto-header detection, custom delimiters |
| JSON | jq integration for filtering and transformation |
| HTTP | REST APIs with caching and custom headers |
| Python | Inline scripts, SQLite queries |
| AWK | Pattern matching, field extraction |
| XML/YAML | Via Python (lxml, PyYAML) |
Security and configuration for production deployments:
- Firewall — Multi-service security for external tools
- Network ACLs — Host pattern matching and restrictions
- Import Restrictions — Python module whitelisting
- File Access Patterns — Read/write permission management
- Preferences — Layered configuration (global, rule-specific, runtime)
Requirements:
- SWI-Prolog 8.0 or higher
- Bash 4.0+ (for associative arrays)
git clone https://github.com/s243a/UnifyWeaver.git
cd UnifyWeaver
# Set up local data directories
./scripts/setup_local.shThe .local/ directory holds project-specific data and tools that are not checked into git:
| Directory | Purpose |
|---|---|
.local/bin/ |
Executable scripts |
.local/data/ |
Cached API responses, scan results, embeddings |
.local/lib/ |
Shared libraries/modules |
.local/tools/ |
External tool repositories |
For Pearltrees integration, clone the harvester tools:
git clone git@github.com:s243a/pt-harvester.git .local/tools/browser-automationUnifyWeaver includes a convenient test environment with auto-discovery:
# Linux/WSL
cd scripts/testing
./init_testing.sh
# Windows (PowerShell)
cd scripts\testing
.\Init-TestEnvironment.ps1Then in the test environment:
?- test_all. % Run all tests
?- test_stream. % Test stream compilation
?- test_recursive. % Test basic recursion
?- test_advanced. % Test advanced recursion patterns
?- test_constraints. % Test constraint system?- use_module(unifyweaver(core/recursive_compiler)).
?- test_recursive_compiler.This generates bash scripts in the output/ directory:
cd output
bash test_recursive.shDefine your Prolog predicates:
% Facts
parent(alice, bob).
parent(bob, charlie).
% Rules
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z).Compile to bash:
?- compile_recursive(ancestor/2, [], BashCode).
?- write_bash_file('ancestor.sh', BashCode).Use the generated script:
source parent.sh
source ancestor.sh
ancestor_all alice # Find all descendants of alice
ancestor_check alice charlie && echo "Yes" || echo "No" # Check specific relationshipSee Extended Documentation for advanced recursion patterns, data sources, and complete examples.
UnifyWeaver follows a modular compilation pipeline:
- Classification - Analyzes predicate to determine recursion pattern
- Constraint Analysis - Detects unique/ordering constraints
- Pattern Matching - Tries tail → linear → tree → mutual → basic recursion
- Optimization - Applies pattern-specific optimizations (BFS, loops, memoization)
- Target Selection - Chooses Bash, PowerShell, or C# backend based on requested
target/1preference - Code Generation / Plan Emission - Renders shell templates, C# source, or query plans for the selected backend
See ARCHITECTURE.md and Extended Documentation for detailed architecture.
Large code templates (50+ lines) are stored as external .mustache files rather than inline format/2 strings. This eliminates Prolog escape sequence issues and makes templates easier to read and maintain.
Directory structure:
templates/targets/
├── c/transitive_closure.mustache
├── cpp/transitive_closure.mustache
├── rust/transitive_closure.mustache
├── go/transitive_closure.mustache
├── ruby/transitive_closure.mustache
├── perl/transitive_closure.mustache
├── python/transitive_closure.mustache
├── ... (18 target directories)
How it works:
Templates use {{placeholder}} syntax and are rendered via template_system:render_template/3:
%% Helper: load and render a target-specific mustache template
compile_tc_from_template(Target, Pred, BasePred, ExtraDict, Code) :-
atom_string(Target, TargetStr),
format(string(Path), 'templates/targets/~w/transitive_closure.mustache', [TargetStr]),
read_file_to_string(Path, Template, []),
append([pred=PredStr, base=BaseStr], ExtraDict, Dict),
template_system:render_template(Template, Dict, Code).Common placeholders: {{pred}} (predicate name), {{base}} (base relation name), {{pred_cap}} (capitalized predicate name for class/struct names).
ancestor(X, Y) % Transitive closure of parent
descendant(X, Y) % Reverse of ancestor
sibling(X, Y) % Same parent, different children% CSV/TSV data processing
:- source(csv, users, [csv_file('data/users.csv'), has_header(true)]).
% AWK text processing
:- source(awk, extract_fields, [
awk_program('$3 > 100 { print $1, $2 }'),
input_file('data.txt')
]).
% HTTP API integration with caching
:- source(http, github_repos, [
url('https://api.github.com/users/octocat/repos'),
cache_duration(3600)
]).
% Python with SQLite
:- source(python, get_users, [
sqlite_query('SELECT name, age FROM users WHERE active = 1'),
database('app.db')
]).
% JSON processing with jq
:- source(json, extract_names, [
jq_filter('.users[] | {name, email} | @tsv'),
json_file('data.json')
]).See Extended Documentation for complete examples.
% Compile predicates to a chained Python pipeline
compile_pipeline(
[parse_user/2, filter_adult/2, format_output/3],
[runtime(cpython), pipeline_name(user_pipeline)],
PythonCode
).Generated Python uses efficient generator chaining:
def user_pipeline(input_stream):
"""Chained pipeline: [parse_user, filter_adult, format_output]"""
yield from format_output(filter_adult(parse_user(input_stream)))For cross-runtime workflows (Python + C#):
compile_pipeline(
[python:extract/1, csharp:validate/1, python:transform/1],
[pipeline_name(data_processor)],
Code
).- Divide-and-conquer patterns (quicksort, mergesort) not yet supported
- Tree recursion uses list representation only
cd scripts/testing
./init_testing.sh # or Init-TestEnvironment.ps1 on WindowsIn SWI-Prolog:
?- test_all. % Run all tests
?- test_stream. % Stream compilation
?- test_recursive. % Basic recursion
?- test_advanced. % Advanced patternsSee TESTING_GUIDE.md for adding tests.
| Resource | Description |
|---|---|
| Educational Materials | 13-book series covering all targets and patterns |
| Extended Documentation | Tutorials and advanced examples |
| Architecture | System design and compilation pipeline |
| Enhanced Pipeline Chaining | Fan-out, merge, routing, and filter stages |
| Cross-Target Glue | Multi-language pipeline composition |
| Advanced Recursion | Recursion patterns deep dive |
| Testing Guide | Testing infrastructure |
Issues and pull requests welcome! See CONTRIBUTING.md for details.
Key areas:
- Additional recursion patterns (divide-and-conquer, N-ary trees)
- Performance optimizations
- Additional data source plugins
- Native PowerShell code generation (pure mode enhancements)
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Developed as an exploration of compiling declarative logic to efficient executable code across multiple target languages—making Prolog's power accessible everywhere from shell scripts to native binaries to database queries.
Contributors:
- John William Creighton (@s243a) - Core development
- GPT-5/5.1-Codex (via OpenAI) - Fixed-point architecture, query engine, generator approaches
- Gemini (via gemini-cli) - Constraint awareness features
- Claude (via Claude Code) - Advanced recursion system, test infrastructure, educational materials