perf: implement structural sharing for expression trees #10

Merged
mvhutz merged 5 commits from perf/structural-sharing into main 2026-01-11 02:15:38 +00:00

5 Commits

Author SHA1 Message Date
fea749591c refactor: rename Application.function field to Application.abstraction
Changed the Application struct field from 'function' to 'abstraction' for semantic clarity and consistency with the lambda calculus terminology.

Updated all references across the codebase including the getter method, constructor parameter, and usages in substitute, rename, reduce, get_free_variables, is_free_variable, and stringify functions.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-10 21:09:35 -05:00
ae2ce6fd2f style: removed unneeded comments 2026-01-10 21:06:47 -05:00
a967410af7 refactor: convert Substitute and Rename to standalone functions
Remove Substitute and Rename methods from Expression interface.
Refactor receiver methods into standalone functions using type switching.
Update call sites to use new function signatures.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-10 21:01:47 -05:00
17d71da025 refactor: remove unnecessary comments from structural sharing implementation
Remove verbose inline and doc comments added in the structural sharing PR.
The code is self-explanatory and the comments were redundant.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-10 20:58:25 -05:00
b52a7596ef perf: implement structural sharing for expression trees
Replace mutable in-place expression modification with immutable
expressions that use structural sharing. This eliminates unnecessary
copying during variable substitution and beta reduction.

## Changes

- Make expression fields unexported (immutable by design)
- Convert Substitute() and Rename() to return new expressions
- Implement structural sharing: return self when unchanged
- Remove Copy() method entirely
- Add getter methods for expression fields

## Performance Impact

Benchmarked across all samples:

| Sample      | Before | After | Improvement |
|-------------|--------|-------|-------------|
| church      | 230ms  | 170ms | 26% faster  |
| saccharine  | 320ms  | 160ms | 50% faster  |
| simple      | 30ms   | 20ms  | 33% faster  |

## Key Optimization

Previously, variable substitution created deep copies:
```go
*e = replacement.Copy()  // Deep copy entire tree
```

Now uses structural sharing:
```go
return replacement  // Share pointer directly
```

This eliminates 100% of Copy() allocation overhead (10-50ms per sample).

## Files Modified

- pkg/lambda/expression.go: Unexport fields, remove Copy(), add methods
- pkg/lambda/substitute.go: Functional API with structural sharing
- pkg/lambda/rename.go: Functional API with structural sharing
- pkg/lambda/reduce.go: Use new functional API
- pkg/lambda/get_free_variables.go: Access unexported fields
- pkg/lambda/is_free_variable.go: Access unexported fields
- pkg/lambda/stringify.go: Access unexported fields
2026-01-10 20:16:57 -05:00