refactor: convert Substitute and Rename to standalone functions
Remove Substitute and Rename methods from Expression interface. Refactor receiver methods into standalone functions using type switching. Update call sites to use new function signatures. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,6 @@ package lambda
|
||||
// Expression represents an immutable lambda calculus expression.
|
||||
type Expression interface {
|
||||
Accept(Visitor)
|
||||
Substitute(target string, replacement Expression) Expression
|
||||
Rename(target string, newName string) Expression
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------- */
|
||||
|
||||
@@ -13,7 +13,7 @@ func ReduceOnce(e *Expression) bool {
|
||||
stack.Push(&typed.body)
|
||||
case *Application:
|
||||
if fn, fnOk := typed.function.(*Abstraction); fnOk {
|
||||
reduced := fn.body.Substitute(fn.parameter, typed.argument)
|
||||
reduced := Substitute(fn.body, fn.parameter, typed.argument)
|
||||
*top = reduced
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,37 +1,39 @@
|
||||
package lambda
|
||||
|
||||
// Rename replaces all occurrences of target variable with newName.
|
||||
func (v *Variable) Rename(target string, newName string) Expression {
|
||||
if v.value == target {
|
||||
return NewVariable(newName)
|
||||
func Rename(expr Expression, target string, newName string) Expression {
|
||||
switch e := expr.(type) {
|
||||
case *Variable:
|
||||
if e.value == target {
|
||||
return NewVariable(newName)
|
||||
}
|
||||
return e
|
||||
|
||||
case *Abstraction:
|
||||
newParam := e.parameter
|
||||
if e.parameter == target {
|
||||
newParam = newName
|
||||
}
|
||||
|
||||
newBody := Rename(e.body, target, newName)
|
||||
|
||||
if newParam == e.parameter && newBody == e.body {
|
||||
return e
|
||||
}
|
||||
|
||||
return NewAbstraction(newParam, newBody)
|
||||
|
||||
case *Application:
|
||||
newFunc := Rename(e.function, target, newName)
|
||||
newArg := Rename(e.argument, target, newName)
|
||||
|
||||
if newFunc == e.function && newArg == e.argument {
|
||||
return e
|
||||
}
|
||||
|
||||
return NewApplication(newFunc, newArg)
|
||||
|
||||
default:
|
||||
return expr
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Rename replaces all occurrences of target variable with newName.
|
||||
func (a *Abstraction) Rename(target string, newName string) Expression {
|
||||
newParam := a.parameter
|
||||
if a.parameter == target {
|
||||
newParam = newName
|
||||
}
|
||||
|
||||
newBody := a.body.Rename(target, newName)
|
||||
|
||||
if newParam == a.parameter && newBody == a.body {
|
||||
return a
|
||||
}
|
||||
|
||||
return NewAbstraction(newParam, newBody)
|
||||
}
|
||||
|
||||
// Rename replaces all occurrences of target variable with newName.
|
||||
func (a *Application) Rename(target string, newName string) Expression {
|
||||
newFunc := a.function.Rename(target, newName)
|
||||
newArg := a.argument.Rename(target, newName)
|
||||
|
||||
if newFunc == a.function && newArg == a.argument {
|
||||
return a
|
||||
}
|
||||
|
||||
return NewApplication(newFunc, newArg)
|
||||
}
|
||||
|
||||
@@ -1,45 +1,47 @@
|
||||
package lambda
|
||||
|
||||
// Substitute replaces all free occurrences of target with replacement.
|
||||
func (v *Variable) Substitute(target string, replacement Expression) Expression {
|
||||
if v.value == target {
|
||||
return replacement
|
||||
func Substitute(expr Expression, target string, replacement Expression) Expression {
|
||||
switch e := expr.(type) {
|
||||
case *Variable:
|
||||
if e.value == target {
|
||||
return replacement
|
||||
}
|
||||
return e
|
||||
|
||||
case *Abstraction:
|
||||
if e.parameter == target {
|
||||
return e
|
||||
}
|
||||
|
||||
body := e.body
|
||||
param := e.parameter
|
||||
if IsFreeVariable(param, replacement) {
|
||||
freeVars := GetFreeVariables(replacement)
|
||||
freeVars.Merge(GetFreeVariables(body))
|
||||
freshVar := GenerateFreshName(freeVars)
|
||||
body = Rename(body, param, freshVar)
|
||||
param = freshVar
|
||||
}
|
||||
|
||||
newBody := Substitute(body, target, replacement)
|
||||
if newBody == body && param == e.parameter {
|
||||
return e
|
||||
}
|
||||
|
||||
return NewAbstraction(param, newBody)
|
||||
|
||||
case *Application:
|
||||
newFunc := Substitute(e.function, target, replacement)
|
||||
newArg := Substitute(e.argument, target, replacement)
|
||||
|
||||
if newFunc == e.function && newArg == e.argument {
|
||||
return e
|
||||
}
|
||||
|
||||
return NewApplication(newFunc, newArg)
|
||||
|
||||
default:
|
||||
return expr
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Substitute replaces all free occurrences of target with replacement.
|
||||
func (a *Abstraction) Substitute(target string, replacement Expression) Expression {
|
||||
if a.parameter == target {
|
||||
return a
|
||||
}
|
||||
|
||||
body := a.body
|
||||
param := a.parameter
|
||||
if IsFreeVariable(param, replacement) {
|
||||
freeVars := GetFreeVariables(replacement)
|
||||
freeVars.Merge(GetFreeVariables(body))
|
||||
freshVar := GenerateFreshName(freeVars)
|
||||
body = body.Rename(param, freshVar)
|
||||
param = freshVar
|
||||
}
|
||||
|
||||
newBody := body.Substitute(target, replacement)
|
||||
if newBody == body && param == a.parameter {
|
||||
return a
|
||||
}
|
||||
|
||||
return NewAbstraction(param, newBody)
|
||||
}
|
||||
|
||||
// Substitute replaces all free occurrences of target with replacement.
|
||||
func (a *Application) Substitute(target string, replacement Expression) Expression {
|
||||
newFunc := a.function.Substitute(target, replacement)
|
||||
newArg := a.argument.Substitute(target, replacement)
|
||||
|
||||
if newFunc == a.function && newArg == a.argument {
|
||||
return a
|
||||
}
|
||||
|
||||
return NewApplication(newFunc, newArg)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user