UnifyWeaver

PowerShell as a Target Language

Status: Implemented (Phase 1 - Bash Wrapper Approach) Version: 1.0.0 Date: 2025-10-19


Overview

UnifyWeaver can now compile Prolog predicates to PowerShell scripts! This document explains how PowerShell compilation works, how to use it, and what to expect.

How It Works (Phase 1)

Instead of generating native PowerShell code, we generate bash scripts and wrap them in PowerShell compatibility layer invocations. This approach:

Reuses all existing bash templates - No need to rewrite compilation logic ✅ Leverages the PowerShell compatibility layer - Uses uw-* commands ✅ Provides quick PowerShell support - Minimal new code required ✅ Maintains consistency - PowerShell and bash outputs are identical

Future (Phase 2): Native PowerShell code generation with object pipeline support


Quick Start

1. Compile a Simple Predicate

:- use_module(unifyweaver(core/powershell_compiler)).

?- compile_to_powershell(color/1, Code).
% Generates PowerShell script that wraps bash implementation

2. Save to File

?- compile_to_powershell(
    grandparent/2,
    [output_file('grandparent.ps1')],
    _
).
% Creates grandparent.ps1

3. Run the Generated Script

# First, load the compatibility layer
. .\scripts\init_unify_compat.ps1

# Then run the generated script
.\grandparent.ps1

API Reference

Main Predicates

compile_to_powershell/2

Signature:

compile_to_powershell(+Predicate, -PowerShellCode)

Description: Compiles a Prolog predicate to PowerShell code with default options.

Example:

?- compile_to_powershell(color/1, Code).
Code = "# Generated PowerShell Script\n...".

compile_to_powershell/3

Signature:

compile_to_powershell(+Predicate, +Options, -PowerShellCode)

Description: Compiles a Prolog predicate to PowerShell code with custom options.

Parameters:

Options:

Examples:

% Basic compilation
?- compile_to_powershell(color/1, [], Code).

% Use recursive compiler
?- compile_to_powershell(factorial/2, [compiler(recursive)], Code).

% Tempfile wrapper style
?- compile_to_powershell(process_data/1, [wrapper_style(tempfile)], Code).

% Write to file
?- compile_to_powershell(
    grandparent/2,
    [output_file('output/grandparent.ps1'), script_name(grandparents)],
    _
).

% Disable compatibility check (not recommended)
?- compile_to_powershell(color/1, [compat_check(false)], Code).

Wrapper Styles

Inline (Default)

Pros:

Cons:

Example Output:

$bashScript = @'
#!/bin/bash
# bash implementation here
'@

uw-bash -c $bashScript

Tempfile

Pros:

Cons:

Example Output:

$tempFile = [System.IO.Path]::GetTempFileName() + ".sh"
$bashScript = @'
#!/bin/bash
# bash implementation here
'@

try {
    Set-Content -Path $tempFile -Value $bashScript -Encoding UTF8
    uw-bash $tempFile
} finally {
    Remove-Item $tempFile -ErrorAction SilentlyContinue
}

Generated Script Structure

Typical Generated PowerShell Script

# Generated PowerShell Script
# Script: grandparent.ps1
# Generated by UnifyWeaver PowerShell Compiler
# Generated: 2025-10-19 22:00:00
#
# This script wraps a bash implementation via the PowerShell compatibility layer.
# The bash code is executed using uw-bash from UnifyWeaver compatibility layer.

# Ensure compatibility layer is available
if (-not (Get-Command uw-bash -ErrorAction SilentlyContinue)) {
    Write-Error "UnifyWeaver PowerShell compatibility layer not loaded"
    Write-Host "Please run: . .\scripts\init_unify_compat.ps1" -ForegroundColor Yellow
    exit 1
}

# Embedded bash implementation
$bashScript = @'
#!/bin/bash
# Bash code generated by stream_compiler
awk 'BEGIN {
    # AWK implementation of grandparent/2
    ...
}' "$@"
'@

# Execute via compatibility layer
if ($Input) {
    $Input | uw-bash -c $bashScript
} else {
    uw-bash -c $bashScript
}

Usage Examples

Example 1: Compile Facts

Prolog:

% Define facts
color(red).
color(green).
color(blue).

% Compile to PowerShell
?- compile_to_powershell(color/1, [output_file('colors.ps1')], _).

Generated PowerShell:

# colors.ps1
# (wrapper code omitted for brevity)

$bashScript = @'
#!/bin/bash
awk 'BEGIN {
    print "red"
    print "green"
    print "blue"
}'
'@

uw-bash -c $bashScript

Usage:

. .\scripts\init_unify_compat.ps1
.\colors.ps1
# Output:
# red
# green
# blue

Example 2: Compile Join Query

Prolog:

% Define relationships
parent(tom, bob).
parent(bob, ann).

grandparent(X, Z) :- parent(X, Y), parent(Y, Z).

% Compile to PowerShell
?- compile_to_powershell(grandparent/2, [output_file('grandparent.ps1')], _).

Generated PowerShell:

# grandparent.ps1
# (includes join logic via AWK)

$bashScript = @'
#!/bin/bash
awk 'BEGIN {
    # parent/2 facts
    parent["tom","bob"] = 1
    parent["bob","ann"] = 1

    # Join logic
    for (key in parent) {
        split(key, xy, SUBSEP)
        x = xy[1]; y = xy[2]
        for (key2 in parent) {
            split(key2, yz, SUBSEP)
            if (yz[1] == y) {
                z = yz[2]
                print x "\t" z
            }
        }
    }
}'
'@

uw-bash -c $bashScript

Usage:

.\grandparent.ps1
# Output:
# tom    ann

Example 3: Pipeline Support

Generated scripts support PowerShell pipelines:

# Read data from file and process
Get-Content users.csv | .\process_users.ps1

# Chain multiple scripts
.\get_users.ps1 | .\filter_active.ps1 | .\format_output.ps1

Requirements

Runtime Requirements

  1. PowerShell 5.1 or later
    • Windows PowerShell 5.1 (built-in on Windows 10+)
    • PowerShell 7+ recommended for better cross-platform support
  2. UnifyWeaver PowerShell Compatibility Layer
    • Located in scripts/powershell-compat/
    • Must be loaded before running generated scripts
  3. Bash (via compatibility layer)
    • Git Bash, WSL, or Cygwin
    • Automatically invoked by compatibility layer

Development Requirements

  1. SWI-Prolog 8.0 or later
  2. UnifyWeaver core modules
    • stream_compiler or recursive_compiler
    • powershell_compiler (this module)

How to Use Generated Scripts

Method 1: Manual Compatibility Layer Load

# In PowerShell, one-time per session:
. .\scripts\init_unify_compat.ps1

# Now you can run generated scripts:
.\colors.ps1
.\grandparent.ps1

Method 2: Auto-Load in Profile

Add to your PowerShell profile ($PROFILE):

# Load UnifyWeaver compatibility layer
$UnifyWeaverPath = "C:\path\to\UnifyWeaver"
if (Test-Path "$UnifyWeaverPath\scripts\init_unify_compat.ps1") {
    . "$UnifyWeaverPath\scripts\init_unify_compat.ps1"
}

If you’re sure the compatibility layer is always available:

?- compile_to_powershell(color/1, [compat_check(false)], Code).

This removes the compatibility check from generated scripts, but they’ll fail if uw-bash is not available.


Comparison: PowerShell vs Bash Output

Same Predicate, Two Targets

Prolog:

color(red).
color(green).
color(blue).

Bash Output:

#!/bin/bash
awk 'BEGIN {
    print "red"
    print "green"
    print "blue"
}'

PowerShell Output:

# Generated PowerShell Script
# (wrapper code)

$bashScript = @'
#!/bin/bash
awk 'BEGIN {
    print "red"
    print "green"
    print "blue"
}'
'@

uw-bash -c $bashScript

Key Difference: PowerShell version wraps the same bash code in a PowerShell compatibility layer invocation.

Result: Identical output, different invocation mechanism.


Performance Considerations

Overhead

PowerShell scripts have a small overhead compared to direct bash execution:

Direct Bash:
  Prolog → Bash → AWK → Output

PowerShell (Phase 1):
  Prolog → PowerShell → uw-bash → Bash → AWK → Output
  (Extra layer: PowerShell compatibility wrapper)

Impact:

Mitigation:


Limitations (Phase 1)

Current Limitations

Not True Native PowerShell

No PowerShell Object Pipeline

Requires Bash

Performance Overhead

What Works Well

Text Processing

PowerShell Integration

Cross-Platform


Troubleshooting

Error: “UnifyWeaver PowerShell compatibility layer not loaded”

Solution:

. .\scripts\init_unify_compat.ps1

Error: “uw-bash: command not found”

Cause: Compatibility layer not properly initialized

Solution:

  1. Verify scripts/powershell-compat/init_unify_compat.ps1 exists
  2. Load it: . .\scripts\init_unify_compat.ps1
  3. Check bash is available: bash --version

Generated Script Produces No Output

Possible Causes:

  1. Input data not provided correctly
  2. Bash script has errors
  3. AWK logic issue

Debugging:

# Check if bash code works directly
$bashScript = @'
# ... paste bash code here ...
'@

# Run with uw-bash for debugging
uw-bash -c $bashScript

Permission Denied When Running Script

Solution:

# Set execution policy (one-time)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

# Or bypass for single script
PowerShell -ExecutionPolicy Bypass -File .\script.ps1

Future Enhancements (Phase 2)

Native PowerShell Code Generation

Instead of wrapping bash, generate actual PowerShell code:

Example (Future):

# Native PowerShell (Phase 2)
function Get-Color {
    return @('red', 'green', 'blue')
}

Get-Color

Object Pipeline Support

Convert between Prolog terms and PowerShell objects:

# Pipeline with objects (Phase 2)
$users | ConvertTo-Json | Invoke-PrologQuery | ConvertFrom-Json

PowerShell-Specific Optimizations


Testing

Run Tests

?- [unifyweaver(core/powershell_compiler)].
?- test_powershell_compiler.

Expected Output

╔════════════════════════════════════════╗
║  PowerShell Compiler Tests            ║
╚════════════════════════════════════════╝

[Test 1] Inline wrapper generation
[✓] Inline wrapper contains expected components

[Test 2] Tempfile wrapper generation
[✓] Tempfile wrapper contains expected components

[Test 3] Compilation with various options
[✓] compat_check(false) omits compatibility check
[✓] Default includes compatibility check

╔════════════════════════════════════════╗
║  All PowerShell Compiler Tests Passed ║
╚════════════════════════════════════════╝

Run Demos

?- [examples/powershell_compilation_demo].
?- main.

This will demonstrate all compilation features and generate example PowerShell scripts.


FAQ

Q: Can I run PowerShell scripts without the compatibility layer?

A: No (in Phase 1). The generated scripts require the compatibility layer to invoke bash. Phase 2 will support native PowerShell generation.

Q: Will PowerShell scripts work on Linux/Mac?

A: Yes, if you have PowerShell Core (pwsh) and bash installed. The compatibility layer works cross-platform.

Q: Can I integrate generated scripts with existing PowerShell modules?

A: Yes! Generated scripts are normal PowerShell scripts and can be called from other PowerShell code:

Import-Module MyModule
$data = Get-MyData
$data | .\process_prolog.ps1 | Export-Results

Q: What’s the performance difference vs bash?

A: Phase 1 has ~50-100ms overhead for the PowerShell wrapper. For data processing, this is usually negligible. Phase 2 native generation will eliminate this.

Q: Can I edit the generated PowerShell scripts?

A: Yes, but regenerating will overwrite your changes. Best practice: keep Prolog as source of truth, or copy generated script to a new file for customization.


Summary

What You Get (Phase 1)

✅ Compile Prolog predicates to PowerShell scripts ✅ Reuse all existing bash compilation templates ✅ Integrate with PowerShell workflows ✅ Cross-platform support (Windows/Linux/Mac with PowerShell Core) ✅ Text-based pipeline support

What’s Coming (Phase 2)

⭐ Native PowerShell code generation ⭐ PowerShell object pipeline support ⭐ No bash dependency ⭐ Better performance ⭐ PowerShell-specific optimizations


See Also


Created: 2025-10-19 Authors: John William Creighton (@s243a), Claude Code (Sonnet 4.5)