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
33 lines
866 B
Go
33 lines
866 B
Go
package debruijn
|
|
|
|
// Shift increments all free variable indices in an expression by the given amount.
|
|
// A variable is free if its index is >= the cutoff (depth of nested abstractions).
|
|
// This is necessary when substituting an expression into a different binding context.
|
|
func Shift(expr Expression, amount int, cutoff int) Expression {
|
|
switch e := expr.(type) {
|
|
case *Variable:
|
|
if e.index >= cutoff {
|
|
return NewVariable(e.index+amount, e.label)
|
|
}
|
|
return e
|
|
|
|
case *Abstraction:
|
|
newBody := Shift(e.body, amount, cutoff+1)
|
|
if newBody == e.body {
|
|
return e
|
|
}
|
|
return NewAbstraction(newBody)
|
|
|
|
case *Application:
|
|
newAbs := Shift(e.abstraction, amount, cutoff)
|
|
newArg := Shift(e.argument, amount, cutoff)
|
|
if newAbs == e.abstraction && newArg == e.argument {
|
|
return e
|
|
}
|
|
return NewApplication(newAbs, newArg)
|
|
|
|
default:
|
|
return expr
|
|
}
|
|
}
|