perf: implement structural sharing for expression trees #10
@@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ------------------------------------------------------------------------- */
|
/** ------------------------------------------------------------------------- */
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user