Compare commits
3 Commits
feat/updat
...
35224ee4d7
| Author | SHA1 | Date | |
|---|---|---|---|
|
35224ee4d7
|
|||
|
da9ee0bcb0
|
|||
|
d4f33c1658
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,7 +3,7 @@
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
lambda
|
||||
/lambda
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
|
||||
2
Makefile
2
Makefile
@@ -21,7 +21,7 @@ build:
|
||||
chmod +x ${BINARY_NAME}
|
||||
|
||||
run: build
|
||||
./${BINARY_NAME} -f ./samples/$(TEST).txt -o program.out
|
||||
./${BINARY_NAME} -s -f ./samples/$(TEST).txt -o program.out
|
||||
|
||||
profile: build
|
||||
./${BINARY_NAME} -p profile/cpu.prof -f ./samples/$(TEST).txt -o program.out
|
||||
|
||||
@@ -51,11 +51,11 @@ func runSample(samplePath string) error {
|
||||
// Benchmark all samples using sub-benchmarks.
|
||||
func BenchmarkSamples(b *testing.B) {
|
||||
samples := map[string]string{
|
||||
"Church": "../../samples/church.txt",
|
||||
"Fast": "../../samples/fast.txt",
|
||||
"Saccharine": "../../samples/saccharine.txt",
|
||||
"Simple": "../../samples/simple.txt",
|
||||
"Thunk": "../../samples/thunk.txt",
|
||||
"Church": "../../samples/church.test",
|
||||
"Fast": "../../samples/fast.test",
|
||||
"Saccharine": "../../samples/saccharine.test",
|
||||
"Simple": "../../samples/simple.test",
|
||||
"Thunk": "../../samples/thunk.test",
|
||||
}
|
||||
|
||||
for name, path := range samples {
|
||||
|
||||
@@ -24,9 +24,9 @@ func New(config *config.Config, expression *lambda.Expression) *Engine {
|
||||
func (e Engine) Run() {
|
||||
e.Emit("start")
|
||||
|
||||
for lambda.ReduceOnce(e.Expression) {
|
||||
lambda.ReduceAll(e.Expression, func() {
|
||||
e.Emit("step")
|
||||
}
|
||||
})
|
||||
|
||||
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
|
||||
}
|
||||
59
pkg/lambda/iterator.go
Normal file
59
pkg/lambda/iterator.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package lambda
|
||||
|
||||
type Iterator struct {
|
||||
trace []*Expression
|
||||
}
|
||||
|
||||
func NewIterator(expr *Expression) *Iterator {
|
||||
return &Iterator{
|
||||
trace: []*Expression{expr},
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Iterator) Current() *Expression {
|
||||
if len(i.trace) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return i.trace[len(i.trace)-1]
|
||||
}
|
||||
|
||||
func (i *Iterator) Parent() *Expression {
|
||||
if len(i.trace) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return i.trace[len(i.trace)-2]
|
||||
}
|
||||
|
||||
func (i *Iterator) Next() {
|
||||
switch typed := (*i.Current()).(type) {
|
||||
case *Abstraction:
|
||||
i.trace = append(i.trace, &typed.body)
|
||||
case *Application:
|
||||
i.trace = append(i.trace, &typed.abstraction)
|
||||
case *Variable:
|
||||
for len(i.trace) > 1 {
|
||||
if app, ok := (*i.Parent()).(*Application); ok {
|
||||
if app.abstraction == *i.Current() {
|
||||
i.Back()
|
||||
i.trace = append(i.trace, &app.argument)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i.Back()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package lambda
|
||||
|
||||
import "git.maximhutz.com/max/lambda/pkg/fifo"
|
||||
import (
|
||||
"git.maximhutz.com/max/lambda/pkg/lifo"
|
||||
)
|
||||
|
||||
func ReduceOnce(e *Expression) bool {
|
||||
stack := fifo.New(e)
|
||||
stack := lifo.New(e)
|
||||
|
||||
for !stack.Empty() {
|
||||
top := stack.MustPop()
|
||||
@@ -13,8 +15,7 @@ func ReduceOnce(e *Expression) bool {
|
||||
stack.Push(&typed.body)
|
||||
case *Application:
|
||||
if fn, fnOk := typed.abstraction.(*Abstraction); fnOk {
|
||||
reduced := Substitute(fn.body, fn.parameter, typed.argument)
|
||||
*top = reduced
|
||||
*top = Substitute(fn.body, fn.parameter, typed.argument)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -25,3 +26,35 @@ func ReduceOnce(e *Expression) bool {
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
0 := \f.\x.x
|
||||
inc n := \f x.(f (n f x))
|
||||
exp n m := (m n)
|
||||
|
||||
N := (inc (inc (inc (inc (inc 0)))))
|
||||
|
||||
(exp N N)
|
||||
@@ -1,11 +0,0 @@
|
||||
fix f := (\x.(f (x x)) \x.(f (x x)))
|
||||
|
||||
inc := (fix \self.\l.(((l \x.\y.x) ((((l \x.\y.y) \x.\y.x) \c.((c \x.\y.x) \c.((c \x.\y.y) (self ((l \x.\y.y) \x.\y.y))))) \c.((c \x.\y.x) \c.((c \x.\y.x) ((l \x.\y.y) \x.\y.y))))) \c.((c \x.\y.x) \c.((c \x.\y.x) \VAR0.\x.\y.y))))
|
||||
one := \c.((c \x.\y.x) \c.((c \x.\y.x) \VAR0.\x.\y.y))
|
||||
double := \N.\c.((c \x.\y.x) \c.((c \x.\y.y) N))
|
||||
print := (fix \self.\l.(((l \x.\y.x) (((((l \x.\y.y) \x.\y.x) 1) 0) (self ((l \x.\y.y) \x.\y.y)))) END))
|
||||
|
||||
|
||||
N := \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.y) \c.((c \x.\y.x) \c.((c \x.\y.x) \VAR0.\x.\y.y))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
|
||||
|
||||
(print N)
|
||||
@@ -1,52 +0,0 @@
|
||||
T x y := x
|
||||
F x y := y
|
||||
if b t e := (b t e)
|
||||
|
||||
pair a b := \c.(c a b)
|
||||
left p := (p T)
|
||||
right p := (p F)
|
||||
|
||||
print n := (n 0 1 end)
|
||||
|
||||
fix f := (\x.(f (x x)) \x.(f (x x)))
|
||||
|
||||
some x := (pair T x)
|
||||
none := \.F
|
||||
isfull := left
|
||||
unwrap := right
|
||||
|
||||
nil := none
|
||||
push i l := (some (pair i l))
|
||||
peek l := (left (unwrap l))
|
||||
pop l := (right (unwrap l))
|
||||
|
||||
inc := (fix \self l.{
|
||||
(if (isfull l)
|
||||
(if (peek l)
|
||||
(push F (self (pop l)))
|
||||
(push T (pop l))
|
||||
)
|
||||
(push T nil)
|
||||
)
|
||||
})
|
||||
|
||||
print := (fix \self l.{
|
||||
(if (isfull l)
|
||||
((if (peek l) 1 0) (self (pop l)))
|
||||
END
|
||||
)
|
||||
})
|
||||
|
||||
one := (push T nil)
|
||||
double N := (push F N)
|
||||
|
||||
N :=
|
||||
(double (double (double (double (double
|
||||
(double (double (double (double (double
|
||||
(double (double (double (double (double
|
||||
(double (double (double (double (double
|
||||
(double (double (double (double (double
|
||||
(double (double (double (double (double
|
||||
one))))))))))))))))))))))))))))))
|
||||
|
||||
(print N)
|
||||
@@ -1,16 +0,0 @@
|
||||
(\0.
|
||||
(\inc.
|
||||
(\add.
|
||||
(\mult.
|
||||
(\exp.
|
||||
(exp (inc (inc (inc (inc 0)))) (inc (inc (inc (inc (inc 0))))))
|
||||
\n m.(m n)
|
||||
)
|
||||
\m n f.(m (n f))
|
||||
)
|
||||
\n m.(m inc n)
|
||||
)
|
||||
\n f x.(f (n f x))
|
||||
)
|
||||
\f x.x
|
||||
)
|
||||
@@ -1 +0,0 @@
|
||||
(\.VALUE anything)
|
||||
Reference in New Issue
Block a user