refactor: extract Reducer interface and update engine to use abstractions
Introduce reducer.Reducer interface and update the engine to use abstract expr.Expression and reducer.Reducer types, enabling pluggable reduction strategies. - Add pkg/reducer/reducer.go with Reducer interface. - Add pkg/lambda/reducer.go with NormalOrderReducer implementation. - Update engine to accept expr.Expression and reducer.Reducer. - Update plugins to use expr.Expression directly (no pointer dereference). - Update main and tests to pass reducer to engine. Closes #30
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
|||||||
"git.maximhutz.com/max/lambda/internal/engine"
|
"git.maximhutz.com/max/lambda/internal/engine"
|
||||||
"git.maximhutz.com/max/lambda/internal/plugins"
|
"git.maximhutz.com/max/lambda/internal/plugins"
|
||||||
"git.maximhutz.com/max/lambda/pkg/convert"
|
"git.maximhutz.com/max/lambda/pkg/convert"
|
||||||
|
"git.maximhutz.com/max/lambda/pkg/lambda"
|
||||||
"git.maximhutz.com/max/lambda/pkg/saccharine"
|
"git.maximhutz.com/max/lambda/pkg/saccharine"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,8 +34,9 @@ func main() {
|
|||||||
compiled := convert.SaccharineToLambda(ast)
|
compiled := convert.SaccharineToLambda(ast)
|
||||||
logger.Info("compiled λ expression", "tree", compiled.String())
|
logger.Info("compiled λ expression", "tree", compiled.String())
|
||||||
|
|
||||||
// Create reduction engine.
|
// Create reduction engine with normal order reducer.
|
||||||
process := engine.New(options, &compiled)
|
reducer := lambda.NewNormalOrderReducer()
|
||||||
|
process := engine.New(options, compiled, reducer)
|
||||||
|
|
||||||
// If the user selected to track CPU performance, attach a profiler to the
|
// If the user selected to track CPU performance, attach a profiler to the
|
||||||
// process.
|
// process.
|
||||||
@@ -61,7 +63,7 @@ func main() {
|
|||||||
process.Run()
|
process.Run()
|
||||||
|
|
||||||
// Return the final reduced result.
|
// Return the final reduced result.
|
||||||
result := (*process.Expression).String()
|
result := process.Expression.String()
|
||||||
err = options.Destination.Write(result)
|
err = options.Destination.Write(result)
|
||||||
cli.HandleError(err)
|
cli.HandleError(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,12 @@ func runSample(samplePath string) (string, error) {
|
|||||||
Verbose: false,
|
Verbose: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and run the engine.
|
// Create and run the engine with normal order reducer.
|
||||||
process := engine.New(cfg, &compiled)
|
reducer := lambda.NewNormalOrderReducer()
|
||||||
|
process := engine.New(cfg, compiled, reducer)
|
||||||
process.Run()
|
process.Run()
|
||||||
|
|
||||||
return lambda.Stringify(compiled) + "\n", nil
|
return process.Expression.String() + "\n", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that all samples produce expected output.
|
// Test that all samples produce expected output.
|
||||||
|
|||||||
@@ -5,30 +5,34 @@ package engine
|
|||||||
import (
|
import (
|
||||||
"git.maximhutz.com/max/lambda/internal/config"
|
"git.maximhutz.com/max/lambda/internal/config"
|
||||||
"git.maximhutz.com/max/lambda/pkg/emitter"
|
"git.maximhutz.com/max/lambda/pkg/emitter"
|
||||||
"git.maximhutz.com/max/lambda/pkg/lambda"
|
"git.maximhutz.com/max/lambda/pkg/expr"
|
||||||
|
"git.maximhutz.com/max/lambda/pkg/reducer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A process for reducing one expression.
|
// Engine is a process for reducing one expression.
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
Config *config.Config
|
Config *config.Config
|
||||||
Expression *lambda.Expression
|
Expression expr.Expression
|
||||||
|
Reducer reducer.Reducer
|
||||||
emitter.BaseEmitter[Event]
|
emitter.BaseEmitter[Event]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new engine, given an unreduced λ-expression.
|
// New creates a new engine with the given expression and reducer.
|
||||||
func New(config *config.Config, expression *lambda.Expression) *Engine {
|
func New(config *config.Config, expression expr.Expression, reducer reducer.Reducer) *Engine {
|
||||||
return &Engine{
|
return &Engine{
|
||||||
Config: config,
|
Config: config,
|
||||||
Expression: expression,
|
Expression: expression,
|
||||||
|
Reducer: reducer,
|
||||||
BaseEmitter: *emitter.New[Event](),
|
BaseEmitter: *emitter.New[Event](),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin the reduction process.
|
// Run begins the reduction process.
|
||||||
func (e *Engine) Run() {
|
func (e *Engine) Run() {
|
||||||
e.Emit(StartEvent)
|
e.Emit(StartEvent)
|
||||||
|
|
||||||
lambda.ReduceAll(e.Expression, func() {
|
e.Expression = e.Reducer.Reduce(e.Expression, func(reduced expr.Expression) {
|
||||||
|
e.Expression = reduced
|
||||||
e.Emit(StepEvent)
|
e.Emit(StepEvent)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -19,5 +19,5 @@ func NewLogs(logger *slog.Logger, process *engine.Engine) *Logs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Logs) Step() {
|
func (t *Logs) Step() {
|
||||||
t.logger.Info("reduction", "tree", (*t.process.Expression).String())
|
t.logger.Info("reduction", "tree", t.process.Expression.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ func NewExplanation(process *engine.Engine) *Explanation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Explanation) Start() {
|
func (t *Explanation) Start() {
|
||||||
fmt.Println((*t.process.Expression).String())
|
fmt.Println(t.process.Expression.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Explanation) Step() {
|
func (t *Explanation) Step() {
|
||||||
fmt.Println(" =", (*t.process.Expression).String())
|
fmt.Println(" =", t.process.Expression.String())
|
||||||
}
|
}
|
||||||
|
|||||||
33
pkg/lambda/reducer.go
Normal file
33
pkg/lambda/reducer.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package lambda
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.maximhutz.com/max/lambda/pkg/expr"
|
||||||
|
"git.maximhutz.com/max/lambda/pkg/reducer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ensure NormalOrderReducer implements reducer.Reducer.
|
||||||
|
var _ reducer.Reducer = (*NormalOrderReducer)(nil)
|
||||||
|
|
||||||
|
// NormalOrderReducer implements normal order (leftmost-outermost) reduction
|
||||||
|
// for lambda calculus expressions.
|
||||||
|
type NormalOrderReducer struct{}
|
||||||
|
|
||||||
|
// NewNormalOrderReducer creates a new normal order reducer.
|
||||||
|
func NewNormalOrderReducer() *NormalOrderReducer {
|
||||||
|
return &NormalOrderReducer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce performs normal order reduction on a lambda expression.
|
||||||
|
// The expression must be a lambda.Expression; other types are returned unchanged.
|
||||||
|
func (r *NormalOrderReducer) Reduce(e expr.Expression, onStep func(expr.Expression)) expr.Expression {
|
||||||
|
lambdaExpr, ok := e.(Expression)
|
||||||
|
if !ok {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
ReduceAll(&lambdaExpr, func() {
|
||||||
|
onStep(lambdaExpr)
|
||||||
|
})
|
||||||
|
|
||||||
|
return lambdaExpr
|
||||||
|
}
|
||||||
15
pkg/reducer/reducer.go
Normal file
15
pkg/reducer/reducer.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Package reducer provides the abstract Reducer interface for all expression
|
||||||
|
// reduction strategies.
|
||||||
|
package reducer
|
||||||
|
|
||||||
|
import "git.maximhutz.com/max/lambda/pkg/expr"
|
||||||
|
|
||||||
|
// Reducer defines the interface for expression reduction strategies.
|
||||||
|
// Different evaluation modes (normal order, applicative order, SKI combinators,
|
||||||
|
// etc.) implement this interface with their own reduction logic.
|
||||||
|
type Reducer interface {
|
||||||
|
// Reduce performs all reduction steps on the expression, calling onStep
|
||||||
|
// after each reduction.
|
||||||
|
// Returns the final reduced expression.
|
||||||
|
Reduce(e expr.Expression, onStep func(expr.Expression)) expr.Expression
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user