From 1d94fa70ff1efa4a570fbe14a867e3e9c79c483c Mon Sep 17 00:00:00 2001 From: "M.V. Hutz" Date: Sat, 7 Feb 2026 00:12:50 -0500 Subject: [PATCH] feat: new engine format --- .golangci.yml | 2 + cmd/lambda/lambda_reduce.go | 3 +- cmd/lambda/registry.go | 2 +- internal/registry/engine.go | 16 +++++-- internal/registry/process.go | 10 ---- internal/registry/repr.go | 9 ++-- pkg/emitter/emitter.go | 46 ------------------- pkg/emitter/listener.go | 19 -------- pkg/engine/engine.go | 11 +++-- pkg/engine/normalorder/engine.go | 22 ++++----- .../{reduce_one.go => reduce_once.go} | 5 ++ 11 files changed, 45 insertions(+), 100 deletions(-) delete mode 100644 pkg/emitter/emitter.go delete mode 100644 pkg/emitter/listener.go rename pkg/engine/normalorder/{reduce_one.go => reduce_once.go} (75%) diff --git a/.golangci.yml b/.golangci.yml index 9c9494b..1ec3d80 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -160,6 +160,8 @@ linters: arguments: # make error messages clearer - "sayRepetitiveInsteadOfStutters" + # require comments on public interface methods + - "checkPublicInterface" # incrementing an integer variable by 1 is recommended to be done using the `++` operator - name: increment-decrement diff --git a/cmd/lambda/lambda_reduce.go b/cmd/lambda/lambda_reduce.go index 1c67658..6370942 100644 --- a/cmd/lambda/lambda_reduce.go +++ b/cmd/lambda/lambda_reduce.go @@ -77,8 +77,7 @@ func LambdaReduce() *cobra.Command { } // Create process. - process := engine.Load() - err = process.Set(compiled) + process, err := engine.Load(compiled) if err != nil { return err } diff --git a/cmd/lambda/registry.go b/cmd/lambda/registry.go index 320ca0c..968b18a 100644 --- a/cmd/lambda/registry.go +++ b/cmd/lambda/registry.go @@ -15,7 +15,7 @@ func GetRegistry() *registry.Registry { (registry.RegisterCodec(r, convert.Saccharine2Lambda{}, "saccharine", "lambda")) // Engines - (registry.RegisterEngine(r, normalorder.Engine{}, "normalorder", "lambda")) + (registry.RegisterEngine(r, normalorder.NewProcess, "normalorder", "lambda")) // Marshalers (registry.RegisterMarshaler(r, lambda.Marshaler{}, "lambda")) diff --git a/internal/registry/engine.go b/internal/registry/engine.go index 22de088..16b162c 100644 --- a/internal/registry/engine.go +++ b/internal/registry/engine.go @@ -7,7 +7,7 @@ import ( ) type Engine interface { - Load() Process + Load(Repr) (Process, error) Name() string InType() string } @@ -22,8 +22,18 @@ func (e convertedEngine[T]) InType() string { return e.inType } func (e convertedEngine[T]) Name() string { return e.name } -func (e convertedEngine[T]) Load() Process { - return convertedProcess[T]{e.engine.Load(), e.inType} +func (e convertedEngine[T]) Load(r Repr) (Process, error) { + t, ok := r.Data().(T) + if !ok { + return nil, fmt.Errorf("'ncorrent format '%s' for engine '%s'", r.ID(), e.inType) + } + + process, err := e.engine(t) + if err != nil { + return nil, err + } + + return convertedProcess[T]{process, e.inType}, nil } func RegisterEngine[T any](registry *Registry, e engine.Engine[T], name, inType string) error { diff --git a/internal/registry/process.go b/internal/registry/process.go index 256a5a9..d2150dd 100644 --- a/internal/registry/process.go +++ b/internal/registry/process.go @@ -1,8 +1,6 @@ package registry import ( - "fmt" - "git.maximhutz.com/max/lambda/pkg/engine" ) @@ -28,14 +26,6 @@ func (b convertedProcess[T]) Get() (Repr, error) { return NewRepr(b.inType, s), nil } -func (b convertedProcess[T]) Set(r Repr) error { - if t, ok := r.Data().(T); ok { - return b.process.Set(t) - } - - return fmt.Errorf("Incorrent format '%s' for engine '%s'.", r.ID(), b.inType) -} - func (b convertedProcess[T]) Step(i int) bool { return b.process.Step(i) } diff --git a/internal/registry/repr.go b/internal/registry/repr.go index 95f19ab..1288f3c 100644 --- a/internal/registry/repr.go +++ b/internal/registry/repr.go @@ -1,11 +1,14 @@ package registry +// A Repr is a lambda calculus expression. It can have any type of +// representation, so long as that class is known to the registry it is handled +// by. type Repr interface { - // Id returns to name of the objects underlying representation. If is - // assumed that if two Repr objects have the same Id(), they share the same - // representation. + // ID returns the name of the underlying representation. It is assumed that + // if two expressions have the same Id(), they have the same representation. ID() string + // The base expression data. Data() any } diff --git a/pkg/emitter/emitter.go b/pkg/emitter/emitter.go deleted file mode 100644 index 2c34b55..0000000 --- a/pkg/emitter/emitter.go +++ /dev/null @@ -1,46 +0,0 @@ -package emitter - -import "git.maximhutz.com/max/lambda/pkg/set" - -type Emitter[E comparable] interface { - On(E, func()) Listener[E] - Off(Listener[E]) - Emit(E) -} - -type BaseEmitter[E comparable] struct { - listeners map[E]set.Set[Listener[E]] -} - -func (e *BaseEmitter[E]) On(kind E, fn func()) Listener[E] { - if e.listeners[kind] == nil { - e.listeners[kind] = set.New[Listener[E]]() - } - - listener := &BaseListener[E]{kind, fn} - e.listeners[kind].Add(listener) - return listener -} - -func (e *BaseEmitter[E]) Off(listener Listener[E]) { - kind := listener.Kind() - if e.listeners[kind] != nil { - e.listeners[kind].Remove(listener) - } -} - -func (e *BaseEmitter[E]) Emit(event E) { - if e.listeners[event] == nil { - e.listeners[event] = set.New[Listener[E]]() - } - - for listener := range e.listeners[event].Items() { - listener.Run() - } -} - -func New[E comparable]() *BaseEmitter[E] { - return &BaseEmitter[E]{ - listeners: map[E]set.Set[Listener[E]]{}, - } -} diff --git a/pkg/emitter/listener.go b/pkg/emitter/listener.go deleted file mode 100644 index 43c95c6..0000000 --- a/pkg/emitter/listener.go +++ /dev/null @@ -1,19 +0,0 @@ -package emitter - -type Listener[E comparable] interface { - Kind() E - Run() -} - -type BaseListener[E comparable] struct { - kind E - fn func() -} - -func (l BaseListener[E]) Kind() E { - return l.kind -} - -func (l BaseListener[E]) Run() { - l.fn() -} diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 0fcebf3..571b09e 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -1,11 +1,12 @@ +// Package engine defines a general process of reducing a lambda calculus +// expression. package engine -type Engine[T any] interface { - Load() Process[T] -} - +// A Process handles the reduction of a type Process[T any] interface { Get() (T, error) - Set(T) error Step(int) bool } + +// An Engine is an object that handles +type Engine[T any] = func(T) (Process[T], error) diff --git a/pkg/engine/normalorder/engine.go b/pkg/engine/normalorder/engine.go index fcdd362..b6d2b96 100644 --- a/pkg/engine/normalorder/engine.go +++ b/pkg/engine/normalorder/engine.go @@ -1,3 +1,5 @@ +// Package normalorder contains an engine that reduces a 'lambda.Expression' +// in the normal order. package normalorder import ( @@ -5,20 +7,20 @@ import ( "git.maximhutz.com/max/lambda/pkg/lambda" ) -type Process struct { +type process struct { expr lambda.Expression } -func (e Process) Get() (lambda.Expression, error) { +func (e process) Get() (lambda.Expression, error) { return e.expr, nil } -func (e *Process) Set(l lambda.Expression) error { +func (e *process) Set(l lambda.Expression) error { e.expr = l return nil } -func (e *Process) Step(i int) bool { +func (e *process) Step(i int) bool { for range i { next, reduced := ReduceOnce(e.expr) if !reduced { @@ -31,12 +33,10 @@ func (e *Process) Step(i int) bool { return true } -type Engine struct { +// NewProcess creates a new redution process. +func NewProcess(expression lambda.Expression) (engine.Process[lambda.Expression], error) { + return &process{expr: expression}, nil } -func (e Engine) Load() engine.Process[lambda.Expression] { - return &Process{} -} - -var _ engine.Process[lambda.Expression] = (*Process)(nil) -var _ engine.Engine[lambda.Expression] = (*Engine)(nil) +var _ engine.Process[lambda.Expression] = (*process)(nil) +var _ engine.Engine[lambda.Expression] = NewProcess diff --git a/pkg/engine/normalorder/reduce_one.go b/pkg/engine/normalorder/reduce_once.go similarity index 75% rename from pkg/engine/normalorder/reduce_one.go rename to pkg/engine/normalorder/reduce_once.go index e1a8aff..734d6a5 100644 --- a/pkg/engine/normalorder/reduce_one.go +++ b/pkg/engine/normalorder/reduce_once.go @@ -2,6 +2,11 @@ package normalorder import "git.maximhutz.com/max/lambda/pkg/lambda" +// ReduceOnce attempts to apply a single reduction to a lambda expression. +// It returns (1) the final expression (reduced, or not), and (2) whether or not +// a reduction was applied. +// +// If a reduction is not applied, it returns the original expression. func ReduceOnce(e lambda.Expression) (lambda.Expression, bool) { switch e := e.(type) { case lambda.Abstraction: