feat: add De Bruijn indexed reduction engine
Add a new interpreter option (-i debruijn) that uses De Bruijn indices for variable representation, eliminating the need for variable renaming during substitution. - Add -i flag to select interpreter (lambda or debruijn) - Create debruijn package with Expression types (Variable with index, Abstraction without parameter, Application) - Implement shift and substitute operations for De Bruijn indices - Add conversion functions between lambda and De Bruijn representations - Update CLI to support switching between interpreters - Add De Bruijn tests to verify all samples pass Closes #26
This commit is contained in:
76
pkg/debruijn/iterator.go
Normal file
76
pkg/debruijn/iterator.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package debruijn
|
||||
|
||||
// Iterator provides depth-first traversal of De Bruijn expressions.
|
||||
type Iterator struct {
|
||||
trace []*Expression
|
||||
}
|
||||
|
||||
// NewIterator creates a new iterator starting at the given expression.
|
||||
func NewIterator(expr *Expression) *Iterator {
|
||||
return &Iterator{[]*Expression{expr}}
|
||||
}
|
||||
|
||||
// Done returns true when the iterator has finished traversal.
|
||||
func (i *Iterator) Done() bool {
|
||||
return len(i.trace) == 0
|
||||
}
|
||||
|
||||
// Current returns a pointer to the current expression.
|
||||
func (i *Iterator) Current() *Expression {
|
||||
if i.Done() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return i.trace[len(i.trace)-1]
|
||||
}
|
||||
|
||||
// Parent returns a pointer to the parent expression.
|
||||
func (i *Iterator) Parent() *Expression {
|
||||
if len(i.trace) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return i.trace[len(i.trace)-2]
|
||||
}
|
||||
|
||||
// Swap replaces the current expression with the given expression.
|
||||
func (i *Iterator) Swap(with Expression) {
|
||||
current := i.Current()
|
||||
if current != nil {
|
||||
*current = with
|
||||
}
|
||||
}
|
||||
|
||||
// Back moves the iterator back to the parent expression.
|
||||
func (i *Iterator) Back() bool {
|
||||
if i.Done() {
|
||||
return false
|
||||
}
|
||||
|
||||
i.trace = i.trace[:len(i.trace)-1]
|
||||
return true
|
||||
}
|
||||
|
||||
// Next advances the iterator to the next expression in leftmost-outermost order.
|
||||
func (i *Iterator) Next() {
|
||||
switch typed := (*i.Current()).(type) {
|
||||
case *Abstraction:
|
||||
i.trace = append(i.trace, &typed.body)
|
||||
case *Application:
|
||||
i.trace = append(i.trace, &typed.abstraction)
|
||||
case *Variable:
|
||||
for len(i.trace) > 1 {
|
||||
if app, ok := (*i.Parent()).(*Application); ok {
|
||||
if app.abstraction == *i.Current() {
|
||||
i.Back()
|
||||
i.trace = append(i.trace, &app.argument)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i.Back()
|
||||
}
|
||||
|
||||
i.trace = []*Expression{}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user