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
35 lines
989 B
Go
35 lines
989 B
Go
package debruijn
|
|
|
|
// Substitute replaces the variable at the given index with the replacement expression.
|
|
// The replacement is shifted appropriately as we descend into nested abstractions.
|
|
func Substitute(expr Expression, index int, replacement Expression) Expression {
|
|
switch e := expr.(type) {
|
|
case *Variable:
|
|
if e.index == index {
|
|
return replacement
|
|
}
|
|
return e
|
|
|
|
case *Abstraction:
|
|
// When entering an abstraction, increment the target index and shift the
|
|
// replacement to account for the new binding context.
|
|
shiftedReplacement := Shift(replacement, 1, 0)
|
|
newBody := Substitute(e.body, index+1, shiftedReplacement)
|
|
if newBody == e.body {
|
|
return e
|
|
}
|
|
return NewAbstraction(newBody)
|
|
|
|
case *Application:
|
|
newAbs := Substitute(e.abstraction, index, replacement)
|
|
newArg := Substitute(e.argument, index, replacement)
|
|
if newAbs == e.abstraction && newArg == e.argument {
|
|
return e
|
|
}
|
|
return NewApplication(newAbs, newArg)
|
|
|
|
default:
|
|
return expr
|
|
}
|
|
}
|