package lambda func Substitute(e *Expression, target string, replacement Expression) { switch typed := (*e).(type) { case *Variable: if typed.Value == target { *e = replacement.Copy() } case *Abstraction: if typed.Parameter == target { return } if IsFreeVariable(typed.Parameter, replacement) { replacementFreeVars := GetFreeVariables(replacement) used := GetFreeVariables(typed.Body) used.Merge(replacementFreeVars) freshVar := GenerateFreshName(used) Rename(typed, typed.Parameter, freshVar) } Substitute(&typed.Body, target, replacement) case *Application: Substitute(&typed.Abstraction, target, replacement) Substitute(&typed.Argument, target, replacement) } }