perf: implement structural sharing for expression trees #10
@@ -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 {
|
||||
func Rename(expr Expression, target string, newName string) Expression {
|
||||
switch e := expr.(type) {
|
||||
case *Variable:
|
||||
if e.value == target {
|
||||
return NewVariable(newName)
|
||||
}
|
||||
return v
|
||||
}
|
||||
return e
|
||||
|
||||
// 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 {
|
||||
case *Abstraction:
|
||||
newParam := e.parameter
|
||||
if e.parameter == target {
|
||||
newParam = newName
|
||||
}
|
||||
|
||||
newBody := a.body.Rename(target, newName)
|
||||
newBody := Rename(e.body, target, newName)
|
||||
|
||||
if newParam == a.parameter && newBody == a.body {
|
||||
return a
|
||||
if newParam == e.parameter && newBody == e.body {
|
||||
return e
|
||||
}
|
||||
|
||||
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)
|
||||
case *Application:
|
||||
newFunc := Rename(e.function, target, newName)
|
||||
newArg := Rename(e.argument, target, newName)
|
||||
|
||||
if newFunc == a.function && newArg == a.argument {
|
||||
return a
|
||||
if newFunc == e.function && newArg == e.argument {
|
||||
return e
|
||||
}
|
||||
|
||||
return NewApplication(newFunc, newArg)
|
||||
|
||||
default:
|
||||
return expr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
func Substitute(expr Expression, target string, replacement Expression) Expression {
|
||||
switch e := expr.(type) {
|
||||
case *Variable:
|
||||
if e.value == target {
|
||||
return replacement
|
||||
}
|
||||
return v
|
||||
return e
|
||||
|
||||
case *Abstraction:
|
||||
if e.parameter == target {
|
||||
return e
|
||||
}
|
||||
|
||||
// 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
|
||||
body := e.body
|
||||
param := e.parameter
|
||||
if IsFreeVariable(param, replacement) {
|
||||
freeVars := GetFreeVariables(replacement)
|
||||
freeVars.Merge(GetFreeVariables(body))
|
||||
freshVar := GenerateFreshName(freeVars)
|
||||
body = body.Rename(param, freshVar)
|
||||
body = Rename(body, param, freshVar)
|
||||
param = freshVar
|
||||
}
|
||||
|
||||
newBody := body.Substitute(target, replacement)
|
||||
if newBody == body && param == a.parameter {
|
||||
return a
|
||||
newBody := Substitute(body, target, replacement)
|
||||
if newBody == body && param == e.parameter {
|
||||
return e
|
||||
}
|
||||
|
||||
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)
|
||||
case *Application:
|
||||
newFunc := Substitute(e.function, target, replacement)
|
||||
newArg := Substitute(e.argument, target, replacement)
|
||||
|
||||
if newFunc == a.function && newArg == a.argument {
|
||||
return a
|
||||
if newFunc == e.function && newArg == e.argument {
|
||||
return e
|
||||
}
|
||||
|
||||
return NewApplication(newFunc, newArg)
|
||||
|
||||
default:
|
||||
return expr
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user