From 588f4cd521a4f6ca283befc09ac3867db91bb55b Mon Sep 17 00:00:00 2001 From: "M.V. Hutz" Date: Mon, 12 Jan 2026 19:39:48 -0500 Subject: [PATCH] feat: added swap to iterator --- pkg/lambda/iterator.go | 35 ++++++++++++++++++++++------------- pkg/lambda/reduce.go | 36 +++--------------------------------- pkg/lifo/lifo.go | 35 ----------------------------------- 3 files changed, 25 insertions(+), 81 deletions(-) delete mode 100644 pkg/lifo/lifo.go diff --git a/pkg/lambda/iterator.go b/pkg/lambda/iterator.go index 76b711a..31f82f9 100644 --- a/pkg/lambda/iterator.go +++ b/pkg/lambda/iterator.go @@ -5,13 +5,15 @@ type Iterator struct { } func NewIterator(expr *Expression) *Iterator { - return &Iterator{ - trace: []*Expression{expr}, - } + return &Iterator{[]*Expression{expr}} +} + +func (i *Iterator) Done() bool { + return len(i.trace) == 0 } func (i *Iterator) Current() *Expression { - if len(i.trace) < 1 { + if i.Done() { return nil } @@ -26,6 +28,22 @@ func (i *Iterator) Parent() *Expression { return i.trace[len(i.trace)-2] } +func (i *Iterator) Swap(with Expression) { + current := i.Current() + if current != nil { + *current = with + } +} + +func (i *Iterator) Back() bool { + if i.Done() { + return false + } + + i.trace = i.trace[:len(i.trace)-1] + return true +} + func (i *Iterator) Next() { switch typed := (*i.Current()).(type) { case *Abstraction: @@ -48,12 +66,3 @@ func (i *Iterator) Next() { i.trace = []*Expression{} } } - -func (i *Iterator) Back() bool { - if len(i.trace) == 0 { - return false - } - - i.trace = i.trace[:len(i.trace)-1] - return true -} diff --git a/pkg/lambda/reduce.go b/pkg/lambda/reduce.go index 8e56bd0..7bcf50c 100644 --- a/pkg/lambda/reduce.go +++ b/pkg/lambda/reduce.go @@ -1,32 +1,5 @@ package lambda -import ( - "git.maximhutz.com/max/lambda/pkg/lifo" -) - -func ReduceOnce(e *Expression) bool { - stack := lifo.New(e) - - for !stack.Empty() { - top := stack.MustPop() - - switch typed := (*top).(type) { - case *Abstraction: - stack.Push(&typed.body) - case *Application: - if fn, fnOk := typed.abstraction.(*Abstraction); fnOk { - *top = Substitute(fn.body, fn.parameter, typed.argument) - return true - } - - stack.Push(&typed.argument) - stack.Push(&typed.abstraction) - } - } - - return false -} - func IsViable(e *Expression) (*Abstraction, Expression, bool) { if e == nil { return nil, nil, false @@ -42,18 +15,15 @@ func IsViable(e *Expression) (*Abstraction, Expression, bool) { func ReduceAll(e *Expression, step func()) { it := NewIterator(e) - for it.Current() != nil { - current := it.Current() - - if fn, arg, ok := IsViable(current); !ok { + for !it.Done() { + if fn, arg, ok := IsViable(it.Current()); !ok { it.Next() } else { - *current = Substitute(fn.body, fn.parameter, arg) + it.Swap(Substitute(fn.body, fn.parameter, arg)) step() if _, _, ok := IsViable(it.Parent()); ok { it.Back() - } else { } } } diff --git a/pkg/lifo/lifo.go b/pkg/lifo/lifo.go deleted file mode 100644 index 6cc51d1..0000000 --- a/pkg/lifo/lifo.go +++ /dev/null @@ -1,35 +0,0 @@ -package lifo - -import "fmt" - -type LIFO[T any] []T - -func New[T any](items ...T) *LIFO[T] { - l := LIFO[T](items) - return &l -} - -func (l *LIFO[T]) Push(item T) { - *l = append(*l, item) -} - -func (l *LIFO[T]) Empty() bool { - return len(*l) == 0 -} - -func (l *LIFO[T]) MustPop() T { - var item T - - *l, item = (*l)[:len(*l)-1], (*l)[len(*l)-1] - return item -} - -func (l *LIFO[T]) Pop() (T, error) { - var item T - - if l.Empty() { - return item, fmt.Errorf("stack is exhausted") - } - - return l.MustPop(), nil -}