feat: improve reduction algorithm with LIFO-based iterator #15
2
Makefile
2
Makefile
@@ -21,7 +21,7 @@ build:
|
|||||||
chmod +x ${BINARY_NAME}
|
chmod +x ${BINARY_NAME}
|
||||||
|
|
||||||
run: build
|
run: build
|
||||||
./${BINARY_NAME} -f ./samples/$(TEST).txt -o program.out
|
./${BINARY_NAME} -s -f ./samples/$(TEST).txt -o program.out
|
||||||
|
|
||||||
profile: build
|
profile: build
|
||||||
./${BINARY_NAME} -p profile/cpu.prof -f ./samples/$(TEST).txt -o program.out
|
./${BINARY_NAME} -p profile/cpu.prof -f ./samples/$(TEST).txt -o program.out
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ func New(config *config.Config, expression *lambda.Expression) *Engine {
|
|||||||
func (e Engine) Run() {
|
func (e Engine) Run() {
|
||||||
e.Emit("start")
|
e.Emit("start")
|
||||||
|
|
||||||
for lambda.ReduceOnce(e.Expression) {
|
lambda.ReduceAll(e.Expression, func() {
|
||||||
e.Emit("step")
|
e.Emit("step")
|
||||||
}
|
})
|
||||||
|
|
||||||
e.Emit("end")
|
e.Emit("end")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package lambda
|
package lambda
|
||||||
|
|
||||||
import "git.maximhutz.com/max/lambda/pkg/fifo"
|
import (
|
||||||
|
"git.maximhutz.com/max/lambda/pkg/lifo"
|
||||||
|
)
|
||||||
|
|
||||||
func ReduceOnce(e *Expression) bool {
|
func ReduceOnce(e *Expression) bool {
|
||||||
stack := fifo.New(e)
|
stack := lifo.New(e)
|
||||||
|
|
||||||
for !stack.Empty() {
|
for !stack.Empty() {
|
||||||
top := stack.MustPop()
|
top := stack.MustPop()
|
||||||
@@ -13,8 +15,7 @@ func ReduceOnce(e *Expression) bool {
|
|||||||
stack.Push(&typed.body)
|
stack.Push(&typed.body)
|
||||||
case *Application:
|
case *Application:
|
||||||
if fn, fnOk := typed.abstraction.(*Abstraction); fnOk {
|
if fn, fnOk := typed.abstraction.(*Abstraction); fnOk {
|
||||||
reduced := Substitute(fn.body, fn.parameter, typed.argument)
|
*top = Substitute(fn.body, fn.parameter, typed.argument)
|
||||||
*top = reduced
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,3 +26,35 @@ func ReduceOnce(e *Expression) bool {
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsViable(e *Expression) (*Abstraction, Expression, bool) {
|
||||||
|
if e == nil {
|
||||||
|
return nil, nil, false
|
||||||
|
} else if app, appOk := (*e).(*Application); !appOk {
|
||||||
|
return nil, nil, false
|
||||||
|
} else if fn, fnOk := app.abstraction.(*Abstraction); !fnOk {
|
||||||
|
return nil, nil, false
|
||||||
|
} else {
|
||||||
|
return fn, app.argument, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReduceAll(e *Expression, step func()) {
|
||||||
|
it := NewIterator(e)
|
||||||
|
|
||||||
|
for it.Current() != nil {
|
||||||
|
current := it.Current()
|
||||||
|
|
||||||
|
if fn, arg, ok := IsViable(current); !ok {
|
||||||
|
it.Next()
|
||||||
|
} else {
|
||||||
|
*current = Substitute(fn.body, fn.parameter, arg)
|
||||||
|
step()
|
||||||
|
|
||||||
|
if _, _, ok := IsViable(it.Parent()); ok {
|
||||||
|
it.Back()
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
35
pkg/lifo/lifo.go
Normal file
35
pkg/lifo/lifo.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
inc n := \f x.(f (n f x))
|
inc n := \f x.(f (n f x))
|
||||||
exp n m := (m n)
|
exp n m := (m n)
|
||||||
|
|
||||||
N := (inc (inc (inc (inc (inc 0)))))
|
N := (inc (inc (inc (inc (inc (inc 0))))))
|
||||||
|
|
||||||
(exp N N)
|
(exp N N)
|
||||||
|
|||||||
Reference in New Issue
Block a user