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:
119
pkg/debruijn/expression.go
Normal file
119
pkg/debruijn/expression.go
Normal file
@@ -0,0 +1,119 @@
|
||||
// Package debruijn provides De Bruijn indexed lambda calculus expressions.
|
||||
// De Bruijn indices eliminate the need for variable names by using numeric
|
||||
// indices to refer to bound variables, avoiding capture issues during substitution.
|
||||
package debruijn
|
||||
|
||||
import "git.maximhutz.com/max/lambda/pkg/expr"
|
||||
|
||||
// Expression is the interface for all De Bruijn indexed expression types.
|
||||
// It embeds the general expr.Expression interface for cross-mode compatibility.
|
||||
type Expression interface {
|
||||
expr.Expression
|
||||
Accept(Visitor)
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------- */
|
||||
|
||||
// Abstraction represents a lambda abstraction without a named parameter.
|
||||
// In De Bruijn notation, the parameter is implicit and referenced by index 0
|
||||
// within the body.
|
||||
type Abstraction struct {
|
||||
body Expression
|
||||
}
|
||||
|
||||
// Body returns the body of the abstraction.
|
||||
func (a *Abstraction) Body() Expression {
|
||||
return a.body
|
||||
}
|
||||
|
||||
// Accept implements the Visitor pattern.
|
||||
func (a *Abstraction) Accept(v Visitor) {
|
||||
v.VisitAbstraction(a)
|
||||
}
|
||||
|
||||
// String returns the De Bruijn notation string representation.
|
||||
func (a *Abstraction) String() string {
|
||||
return Stringify(a)
|
||||
}
|
||||
|
||||
// NewAbstraction creates a new De Bruijn abstraction with the given body.
|
||||
func NewAbstraction(body Expression) *Abstraction {
|
||||
return &Abstraction{body: body}
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------- */
|
||||
|
||||
// Application represents the application of one expression to another.
|
||||
type Application struct {
|
||||
abstraction Expression
|
||||
argument Expression
|
||||
}
|
||||
|
||||
// Abstraction returns the function expression being applied.
|
||||
func (a *Application) Abstraction() Expression {
|
||||
return a.abstraction
|
||||
}
|
||||
|
||||
// Argument returns the argument expression.
|
||||
func (a *Application) Argument() Expression {
|
||||
return a.argument
|
||||
}
|
||||
|
||||
// Accept implements the Visitor pattern.
|
||||
func (a *Application) Accept(v Visitor) {
|
||||
v.VisitApplication(a)
|
||||
}
|
||||
|
||||
// String returns the De Bruijn notation string representation.
|
||||
func (a *Application) String() string {
|
||||
return Stringify(a)
|
||||
}
|
||||
|
||||
// NewApplication creates a new application expression.
|
||||
func NewApplication(abstraction Expression, argument Expression) *Application {
|
||||
return &Application{abstraction: abstraction, argument: argument}
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------- */
|
||||
|
||||
// Variable represents a De Bruijn indexed variable.
|
||||
// The index indicates how many binders to skip to find the binding abstraction.
|
||||
// The label is an optional hint for display purposes.
|
||||
type Variable struct {
|
||||
index int
|
||||
label string
|
||||
}
|
||||
|
||||
// Index returns the De Bruijn index.
|
||||
func (v *Variable) Index() int {
|
||||
return v.index
|
||||
}
|
||||
|
||||
// Label returns the optional variable label.
|
||||
func (v *Variable) Label() string {
|
||||
return v.label
|
||||
}
|
||||
|
||||
// Accept implements the Visitor pattern.
|
||||
func (v *Variable) Accept(visitor Visitor) {
|
||||
visitor.VisitVariable(v)
|
||||
}
|
||||
|
||||
// String returns the De Bruijn notation string representation.
|
||||
func (v *Variable) String() string {
|
||||
return Stringify(v)
|
||||
}
|
||||
|
||||
// NewVariable creates a new De Bruijn variable with the given index and label.
|
||||
func NewVariable(index int, label string) *Variable {
|
||||
return &Variable{index: index, label: label}
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------- */
|
||||
|
||||
// Visitor interface for traversing De Bruijn expressions.
|
||||
type Visitor interface {
|
||||
VisitAbstraction(*Abstraction)
|
||||
VisitApplication(*Application)
|
||||
VisitVariable(*Variable)
|
||||
}
|
||||
Reference in New Issue
Block a user