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:
2026-01-10 21:01:47 -05:00
parent 17d71da025
commit a967410af7
4 changed files with 77 additions and 75 deletions

View File

@@ -3,8 +3,6 @@ package lambda
// Expression represents an immutable lambda calculus expression. // Expression represents an immutable lambda calculus expression.
type Expression interface { type Expression interface {
Accept(Visitor) Accept(Visitor)
Substitute(target string, replacement Expression) Expression
Rename(target string, newName string) Expression
} }
/** ------------------------------------------------------------------------- */ /** ------------------------------------------------------------------------- */

View File

@@ -13,7 +13,7 @@ func ReduceOnce(e *Expression) bool {
stack.Push(&typed.body) stack.Push(&typed.body)
case *Application: case *Application:
if fn, fnOk := typed.function.(*Abstraction); fnOk { 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 *top = reduced
return true return true
} }

View File

@@ -1,37 +1,39 @@
package lambda package lambda
// Rename replaces all occurrences of target variable with newName. // Rename replaces all occurrences of target variable with newName.
func (v *Variable) Rename(target string, newName string) Expression { func Rename(expr Expression, target string, newName string) Expression {
if v.value == target { switch e := expr.(type) {
return NewVariable(newName) 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)
} }

View File

@@ -1,45 +1,47 @@
package lambda package lambda
// Substitute replaces all free occurrences of target with replacement. // Substitute replaces all free occurrences of target with replacement.
func (v *Variable) Substitute(target string, replacement Expression) Expression { func Substitute(expr Expression, target string, replacement Expression) Expression {
if v.value == target { switch e := expr.(type) {
return replacement 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)
} }