Closes #26 - Added -i flag to select interpreter (lambda or debruijn) - Created debruijn package with Expression interface - Variable contains index and optional label - Abstraction contains only body (no parameter) - Application structure remains similar - Implemented De Bruijn reduction without variable renaming - Shift operation handles index adjustments - Substitute replaces by index instead of name - Abstracted Engine into interface with two implementations - LambdaEngine: original named variable engine - DeBruijnEngine: new index-based engine - Added conversion functions between representations - LambdaToDeBruijn: converts named to indexed - DeBruijnToLambda: converts indexed back to named - SaccharineToDeBruijn: direct saccharine to De Bruijn - Updated main to switch engines based on -i flag - All test samples pass with both engines Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
31 lines
620 B
Go
31 lines
620 B
Go
package debruijn
|
|
|
|
func IsViable(e *Expression) (*Abstraction, Expression, bool) {
|
|
if e == nil {
|
|
return nil, nil, false
|
|
} else if app, appOk := (*e).(*Application); !appOk {
|
|
return nil, nil, false
|
|
} else if fn, fnOk := app.abstraction.(*Abstraction); !fnOk {
|
|
return nil, nil, false
|
|
} else {
|
|
return fn, app.argument, true
|
|
}
|
|
}
|
|
|
|
func ReduceAll(e *Expression, step func()) {
|
|
it := NewIterator(e)
|
|
|
|
for !it.Done() {
|
|
if fn, arg, ok := IsViable(it.Current()); !ok {
|
|
it.Next()
|
|
} else {
|
|
it.Swap(Substitute(fn.body, arg))
|
|
step()
|
|
|
|
if _, _, ok := IsViable(it.Parent()); ok {
|
|
it.Back()
|
|
}
|
|
}
|
|
}
|
|
}
|