perf: implement structural sharing for expression trees #10

Merged
mvhutz merged 5 commits from perf/structural-sharing into main 2026-01-11 02:15:38 +00:00
7 changed files with 17 additions and 17 deletions
Showing only changes of commit fea749591c - Show all commits

View File

@@ -30,12 +30,12 @@ func NewAbstraction(parameter string, body Expression) *Abstraction {
/** ------------------------------------------------------------------------- */ /** ------------------------------------------------------------------------- */
type Application struct { type Application struct {
function Expression abstraction Expression
argument Expression argument Expression
} }
func (a *Application) Function() Expression { func (a *Application) Abstraction() Expression {
return a.function return a.abstraction
} }
func (a *Application) Argument() Expression { func (a *Application) Argument() Expression {
@@ -46,8 +46,8 @@ func (a *Application) Accept(v Visitor) {
v.VisitApplication(a) v.VisitApplication(a)
} }
func NewApplication(function Expression, argument Expression) *Application { func NewApplication(abstraction Expression, argument Expression) *Application {
return &Application{function: function, argument: argument} return &Application{abstraction: abstraction, argument: argument}
} }
/** ------------------------------------------------------------------------- */ /** ------------------------------------------------------------------------- */

View File

@@ -11,7 +11,7 @@ func GetFreeVariables(e Expression) *set.Set[string] {
vars.Remove(e.parameter) vars.Remove(e.parameter)
return vars return vars
case *Application: case *Application:
vars := GetFreeVariables(e.function) vars := GetFreeVariables(e.abstraction)
vars.Merge(GetFreeVariables(e.argument)) vars.Merge(GetFreeVariables(e.argument))
return vars return vars
default: default:

View File

@@ -7,7 +7,7 @@ func IsFreeVariable(n string, e Expression) bool {
case *Abstraction: case *Abstraction:
return e.parameter != n && IsFreeVariable(n, e.body) return e.parameter != n && IsFreeVariable(n, e.body)
case *Application: case *Application:
return IsFreeVariable(n, e.function) || IsFreeVariable(n, e.argument) return IsFreeVariable(n, e.abstraction) || IsFreeVariable(n, e.argument)
default: default:
return false return false
} }

View File

@@ -12,14 +12,14 @@ func ReduceOnce(e *Expression) bool {
case *Abstraction: case *Abstraction:
stack.Push(&typed.body) stack.Push(&typed.body)
case *Application: case *Application:
if fn, fnOk := typed.function.(*Abstraction); fnOk { if fn, fnOk := typed.abstraction.(*Abstraction); fnOk {
reduced := Substitute(fn.body, fn.parameter, typed.argument) reduced := Substitute(fn.body, fn.parameter, typed.argument)
*top = reduced *top = reduced
return true return true
} }
stack.Push(&typed.argument) stack.Push(&typed.argument)
stack.Push(&typed.function) stack.Push(&typed.abstraction)
} }
} }

View File

@@ -23,14 +23,14 @@ func Rename(expr Expression, target string, newName string) Expression {
return NewAbstraction(newParam, newBody) return NewAbstraction(newParam, newBody)
case *Application: case *Application:
newFunc := Rename(e.function, target, newName) newAbs := Rename(e.abstraction, target, newName)
newArg := Rename(e.argument, target, newName) newArg := Rename(e.argument, target, newName)
if newFunc == e.function && newArg == e.argument { if newAbs == e.abstraction && newArg == e.argument {
return e return e
} }
return NewApplication(newFunc, newArg) return NewApplication(newAbs, newArg)
default: default:
return expr return expr

View File

@@ -19,7 +19,7 @@ func (v *stringifyVisitor) VisitAbstraction(f *Abstraction) {
func (v *stringifyVisitor) VisitApplication(c *Application) { func (v *stringifyVisitor) VisitApplication(c *Application) {
v.builder.WriteRune('(') v.builder.WriteRune('(')
c.function.Accept(v) c.abstraction.Accept(v)
v.builder.WriteRune(' ') v.builder.WriteRune(' ')
c.argument.Accept(v) c.argument.Accept(v)
v.builder.WriteRune(')') v.builder.WriteRune(')')

View File

@@ -31,14 +31,14 @@ func Substitute(expr Expression, target string, replacement Expression) Expressi
return NewAbstraction(param, newBody) return NewAbstraction(param, newBody)
case *Application: case *Application:
newFunc := Substitute(e.function, target, replacement) newAbs := Substitute(e.abstraction, target, replacement)
newArg := Substitute(e.argument, target, replacement) newArg := Substitute(e.argument, target, replacement)
if newFunc == e.function && newArg == e.argument { if newAbs == e.abstraction && newArg == e.argument {
return e return e
} }
return NewApplication(newFunc, newArg) return NewApplication(newAbs, newArg)
default: default:
return expr return expr