active library

aperture

Started 2021 HTML

Resources & Distribution

Source Code

Package Registries

Apertures

A minimal Lisp-like language where “holes” (written ?x or ?ns.x) represent unknown values that can be filled later. This enables pausable, resumable evaluation for coordinating computation across distributed systems.

This is a coordination primitive, not a security mechanism. Apertures leak information through program structure and are suitable for honest-but-curious settings where coordination matters more than cryptographic privacy.

Installation

go install github.com/queelius/aperture/cmd/aperture@latest

Or build from source:

git clone https://github.com/queelius/aperture
cd aperture
go build -o aperture ./cmd/aperture

Quick Start

# Start REPL
aperture

# Evaluate an expression
aperture eval "(+ 3 5)"
# => 8

# Partial evaluation with holes
echo "(+ 3 ?x 5)" > template.apt
aperture partial template.apt
# => (+ 8 ?x)

# Fill holes and evaluate
aperture fill --hole x=10 template.apt
# => 18

Core Concepts

Holes (Apertures)

Holes are placeholders for unknown values:

?x           ; Simple hole
?client.x    ; Namespaced hole (for multi-party scenarios)

Partial Evaluation

Expressions with holes are evaluated as far as possible:

(+ 3 ?x 5)        ; => (+ 8 ?x)    ; Constants folded
(* 0 ?anything)   ; => 0           ; Annihilation rule
(* 1 ?x)          ; => ?x          ; Identity rule
(if true ?x ?y)   ; => ?x          ; Conditional elimination

Hole Filling

Fill holes to complete evaluation:

; Given: (+ 8 ?x)
; Fill x=10
; Result: 18

CLI Commands

aperture                        # Start REPL
aperture run <file>             # Execute a file
aperture eval "<expr>"          # Evaluate an expression
aperture partial <file>         # Partial evaluate a file
aperture fill --hole x=10 <file> # Fill holes and evaluate
aperture version                # Show version

REPL Commands

> (define x 10)
> (+ x 5)
15
> :holes (+ ?a ?b)
a b
> :partial (+ 3 ?x 5)
(+ 8 ?x)
> :env
x = 10
> :quit

Language Reference

Data Types

  • Numbers: 42, 3.14, -5, 1e10
  • Strings: "hello", "with\nnewline"
  • Booleans: true, false
  • Symbols: foo, my-var
  • Lists: (1 2 3), (list a b c)
  • Holes: ?x, ?ns.name

Special Forms

(define name value)             ; Define a variable
(define (name args) body)       ; Define a function
(lambda (args) body)            ; Anonymous function
(let ((x 1) (y 2)) body)        ; Local bindings
(if pred then else)             ; Conditional
(cond (p1 e1) (p2 e2) (else e)) ; Multi-way conditional
(quote expr) or 'expr           ; Quote (don't evaluate)
(begin e1 e2 ... en)            ; Sequence

Arithmetic

(+ a b ...)    ; Addition
(- a b)        ; Subtraction
(* a b ...)    ; Multiplication
(/ a b)        ; Division

Comparison

(= a b)        ; Equality
(< a b)        ; Less than
(> a b)        ; Greater than
(<= a b)       ; Less or equal
(>= a b)       ; Greater or equal

Logic

(and a b ...)  ; Short-circuit AND
(or a b ...)   ; Short-circuit OR
(not a)        ; Negation

List Operations

(list a b c)   ; Create list
(head lst)     ; First element
(tail lst)     ; All but first
(append l1 l2) ; Concatenate
(length lst)   ; List length
(empty? lst)   ; True if empty
(nth lst n)    ; Element at index

Hole Operations

(holes expr)   ; List hole names in expr
(ground? expr) ; True if no holes

Client-Server Demo

The demo/query/ directory contains a client-server demo showing the “local computation” pattern from the paper:

# Terminal 1: Start server
go run ./demo/query/server

# Terminal 2: Run client
go run ./demo/query/client '(+ 3 ?x 5)' x=10

Output:

=== Step 1: Send to server for optimization ===
Original: (+ 3 ?x 5)
Optimized: (+ 8 ?x)
Unfilled holes: [x]

=== Step 2: Fill holes locally ===
  x = 10

After fill: (+ 8 10)

=== Step 3: Evaluate locally ===
Result: 18

Library Usage

import (
    "github.com/queelius/aperture/pkg/parser"
    "github.com/queelius/aperture/pkg/eval"
    "github.com/queelius/aperture/pkg/env"
    "github.com/queelius/aperture/pkg/value"
)

// Parse and evaluate
expr, _ := parser.ParseOne("(+ 3 5)")
e := env.Global()
result := eval.Eval(expr, e)
// result = value.Num{Val: 8}

// Partial evaluation
template, _ := parser.ParseOne("(+ 3 ?x 5)")
partial := eval.PartialEval(template, e)
// partial.String() = "(+ 8 ?x)"

// Fill holes
bindings := map[string]value.Value{"x": value.NewNum(10)}
filled := eval.Fill(partial, bindings)
final := eval.Eval(filled, e)
// final = value.Num{Val: 18}

When to Use Apertures

Good for:

  • Coordinating distributed computation where parties already have partial trust
  • Scenarios where query structure isn’t sensitive
  • Local computation with remote optimization assistance
  • Educational tools for teaching distributed computing concepts

NOT for:

  • Adversarial environments (no protection against malicious parties)
  • Scenarios requiring cryptographic privacy guarantees
  • High-stakes privacy requirements (medical records, financial data)
  • Any use case where information leakage is unacceptable

Documentation

License

MIT

Discussion