From dbb988b6336bf43ef2442167765f2ea911d99f74 Mon Sep 17 00:00:00 2001 From: "M.V. Hutz" Date: Sat, 17 Jan 2026 15:02:08 -0500 Subject: [PATCH 1/2] refactor: replace visitor pattern with type-switch recursion Closes #36 --- pkg/lambda/expression.go | 21 ------------------ pkg/lambda/stringify.go | 48 ++++++++++++++++++---------------------- 2 files changed, 22 insertions(+), 47 deletions(-) diff --git a/pkg/lambda/expression.go b/pkg/lambda/expression.go index 91e1502..cb61d19 100644 --- a/pkg/lambda/expression.go +++ b/pkg/lambda/expression.go @@ -6,7 +6,6 @@ import "git.maximhutz.com/max/lambda/pkg/expr" // It embeds the general expr.Expression interface for cross-mode compatibility. type Expression interface { expr.Expression - Accept(Visitor) } /** ------------------------------------------------------------------------- */ @@ -24,10 +23,6 @@ func (a *Abstraction) Body() Expression { return a.body } -func (a *Abstraction) Accept(v Visitor) { - v.VisitAbstraction(a) -} - func (a *Abstraction) String() string { return Stringify(a) } @@ -51,10 +46,6 @@ func (a *Application) Argument() Expression { return a.argument } -func (a *Application) Accept(v Visitor) { - v.VisitApplication(a) -} - func (a *Application) String() string { return Stringify(a) } @@ -73,10 +64,6 @@ func (v *Variable) Value() string { return v.value } -func (v *Variable) Accept(visitor Visitor) { - visitor.VisitVariable(v) -} - func (v *Variable) String() string { return Stringify(v) } @@ -84,11 +71,3 @@ func (v *Variable) String() string { func NewVariable(name string) *Variable { return &Variable{value: name} } - -/** ------------------------------------------------------------------------- */ - -type Visitor interface { - VisitAbstraction(*Abstraction) - VisitApplication(*Application) - VisitVariable(*Variable) -} diff --git a/pkg/lambda/stringify.go b/pkg/lambda/stringify.go index 1d838b2..b914a3a 100644 --- a/pkg/lambda/stringify.go +++ b/pkg/lambda/stringify.go @@ -2,31 +2,27 @@ package lambda import "strings" -type stringifyVisitor struct { - builder strings.Builder -} - -func (v *stringifyVisitor) VisitVariable(a *Variable) { - v.builder.WriteString(a.value) -} - -func (v *stringifyVisitor) VisitAbstraction(f *Abstraction) { - v.builder.WriteRune('\\') - v.builder.WriteString(f.parameter) - v.builder.WriteRune('.') - f.body.Accept(v) -} - -func (v *stringifyVisitor) VisitApplication(c *Application) { - v.builder.WriteRune('(') - c.abstraction.Accept(v) - v.builder.WriteRune(' ') - c.argument.Accept(v) - v.builder.WriteRune(')') -} - +// Stringify converts a lambda calculus expression to its string representation. func Stringify(e Expression) string { - b := &stringifyVisitor{builder: strings.Builder{}} - e.Accept(b) - return b.builder.String() + var builder strings.Builder + stringify(&builder, e) + return builder.String() +} + +func stringify(b *strings.Builder, e Expression) { + switch e := e.(type) { + case *Variable: + b.WriteString(e.value) + case *Abstraction: + b.WriteRune('\\') + b.WriteString(e.parameter) + b.WriteRune('.') + stringify(b, e.body) + case *Application: + b.WriteRune('(') + stringify(b, e.abstraction) + b.WriteRune(' ') + stringify(b, e.argument) + b.WriteRune(')') + } } -- 2.49.1 From 3ef27bc28a3797538dfe0b22643589ebb51ea578 Mon Sep 17 00:00:00 2001 From: "M.V. Hutz" Date: Sat, 17 Jan 2026 15:37:31 -0500 Subject: [PATCH 2/2] feat: fmt.Stringer --- pkg/expr/expr.go | 8 ++++++-- pkg/lambda/expression.go | 22 +++++++++++++++------- pkg/lambda/stringify.go | 28 ---------------------------- 3 files changed, 21 insertions(+), 37 deletions(-) delete mode 100644 pkg/lambda/stringify.go diff --git a/pkg/expr/expr.go b/pkg/expr/expr.go index 4fd8b78..a041966 100644 --- a/pkg/expr/expr.go +++ b/pkg/expr/expr.go @@ -2,10 +2,14 @@ // expression types in the lambda interpreter. package expr +import ( + "fmt" +) + // Expression is the base interface for all evaluatable expression types. // Different evaluation modes (lambda calculus, SKI combinators, typed lambda // calculus, etc.) implement this interface with their own concrete types. type Expression interface { - // String returns a human-readable representation of the expression. - String() string + // The expression should have a human-readable representation. + fmt.Stringer } diff --git a/pkg/lambda/expression.go b/pkg/lambda/expression.go index cb61d19..7cb838a 100644 --- a/pkg/lambda/expression.go +++ b/pkg/lambda/expression.go @@ -1,6 +1,8 @@ package lambda -import "git.maximhutz.com/max/lambda/pkg/expr" +import ( + "git.maximhutz.com/max/lambda/pkg/expr" +) // Expression is the interface for all lambda calculus expression types. // It embeds the general expr.Expression interface for cross-mode compatibility. @@ -15,6 +17,8 @@ type Abstraction struct { body Expression } +var _ Expression = (*Abstraction)(nil) + func (a *Abstraction) Parameter() string { return a.parameter } @@ -24,11 +28,11 @@ func (a *Abstraction) Body() Expression { } func (a *Abstraction) String() string { - return Stringify(a) + return "\\" + a.parameter + "." + a.body.String() } func NewAbstraction(parameter string, body Expression) *Abstraction { - return &Abstraction{parameter: parameter, body: body} + return &Abstraction{parameter, body} } /** ------------------------------------------------------------------------- */ @@ -38,6 +42,8 @@ type Application struct { argument Expression } +var _ Expression = (*Application)(nil) + func (a *Application) Abstraction() Expression { return a.abstraction } @@ -47,11 +53,11 @@ func (a *Application) Argument() Expression { } func (a *Application) String() string { - return Stringify(a) + return "(" + a.abstraction.String() + " " + a.argument.String() + ")" } func NewApplication(abstraction Expression, argument Expression) *Application { - return &Application{abstraction: abstraction, argument: argument} + return &Application{abstraction, argument} } /** ------------------------------------------------------------------------- */ @@ -60,14 +66,16 @@ type Variable struct { value string } +var _ Expression = (*Variable)(nil) + func (v *Variable) Value() string { return v.value } func (v *Variable) String() string { - return Stringify(v) + return v.value } func NewVariable(name string) *Variable { - return &Variable{value: name} + return &Variable{name} } diff --git a/pkg/lambda/stringify.go b/pkg/lambda/stringify.go deleted file mode 100644 index b914a3a..0000000 --- a/pkg/lambda/stringify.go +++ /dev/null @@ -1,28 +0,0 @@ -package lambda - -import "strings" - -// Stringify converts a lambda calculus expression to its string representation. -func Stringify(e Expression) string { - var builder strings.Builder - stringify(&builder, e) - return builder.String() -} - -func stringify(b *strings.Builder, e Expression) { - switch e := e.(type) { - case *Variable: - b.WriteString(e.value) - case *Abstraction: - b.WriteRune('\\') - b.WriteString(e.parameter) - b.WriteRune('.') - stringify(b, e.body) - case *Application: - b.WriteRune('(') - stringify(b, e.abstraction) - b.WriteRune(' ') - stringify(b, e.argument) - b.WriteRune(')') - } -} -- 2.49.1