feat: use iterative approach for reduce once

This commit is contained in:
2025-12-28 02:37:22 -05:00
parent 633d4a4d3b
commit 6be3b7958a
3 changed files with 57 additions and 17 deletions

35
pkg/fifo/fifo.go Normal file
View File

@@ -0,0 +1,35 @@
package fifo
import "fmt"
type FIFO[T any] []T
func New[T any](items ...T) *FIFO[T] {
f := FIFO[T](items)
return &f
}
func (f *FIFO[T]) Push(item T) {
*f = append(*f, item)
}
func (f *FIFO[T]) Empty() bool {
return len(*f) == 0
}
func (f *FIFO[T]) MustPop() T {
var item T
*f, item = (*f)[:len(*f)-1], (*f)[len(*f)-1]
return item
}
func (f *FIFO[T]) Pop() (T, error) {
var item T
if f.Empty() {
return item, fmt.Errorf("stack is exhausted")
}
return f.MustPop(), nil
}

View File

@@ -1,22 +1,27 @@
package lambda package lambda
import "git.maximhutz.com/max/lambda/pkg/fifo"
func ReduceOnce(e *Expression) bool { func ReduceOnce(e *Expression) bool {
switch typed := (*e).(type) { stack := fifo.New(e)
case *Abstraction:
return ReduceOnce(&typed.Body)
case *Application:
if fn, fnOk := typed.Abstraction.(*Abstraction); fnOk {
Substitute(&fn.Body, fn.Parameter, typed.Argument)
*e = fn.Body
return true
}
if ReduceOnce(&typed.Abstraction) { for !stack.Empty() {
return true top := stack.MustPop()
}
return ReduceOnce(&typed.Argument) switch typed := (*top).(type) {
default: case *Abstraction:
return false stack.Push(&typed.Body)
case *Application:
if fn, fnOk := typed.Abstraction.(*Abstraction); fnOk {
Substitute(&fn.Body, fn.Parameter, typed.Argument)
*top = fn.Body
return true
}
stack.Push(&typed.Argument)
stack.Push(&typed.Abstraction)
}
} }
return false
} }

View File

@@ -12,5 +12,5 @@
) )
\n f x.(f (n f x)) \n f x.(f (n f x))
) )
\f x.((((((x)))))) \f x.x
) )