feat: registry, normalorder engine, lambda codec and marshaler
This commit is contained in:
@@ -3,16 +3,17 @@ package convert
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.maximhutz.com/max/lambda/pkg/codec"
|
||||
"git.maximhutz.com/max/lambda/pkg/lambda"
|
||||
"git.maximhutz.com/max/lambda/pkg/saccharine"
|
||||
)
|
||||
|
||||
func convertAtom(n *saccharine.Atom) lambda.Expression {
|
||||
func encodeAtom(n *saccharine.Atom) lambda.Expression {
|
||||
return lambda.NewVariable(n.Name)
|
||||
}
|
||||
|
||||
func convertAbstraction(n *saccharine.Abstraction) lambda.Expression {
|
||||
result := SaccharineToLambda(n.Body)
|
||||
func encodeAbstraction(n *saccharine.Abstraction) lambda.Expression {
|
||||
result := encodeExpression(n.Body)
|
||||
|
||||
parameters := n.Parameters
|
||||
|
||||
@@ -31,13 +32,13 @@ func convertAbstraction(n *saccharine.Abstraction) lambda.Expression {
|
||||
return result
|
||||
}
|
||||
|
||||
func convertApplication(n *saccharine.Application) lambda.Expression {
|
||||
result := SaccharineToLambda(n.Abstraction)
|
||||
func encodeApplication(n *saccharine.Application) lambda.Expression {
|
||||
result := encodeExpression(n.Abstraction)
|
||||
|
||||
arguments := []lambda.Expression{}
|
||||
for _, argument := range n.Arguments {
|
||||
convertedArgument := SaccharineToLambda(argument)
|
||||
arguments = append(arguments, convertedArgument)
|
||||
encodeedArgument := encodeExpression(argument)
|
||||
arguments = append(arguments, encodeedArgument)
|
||||
}
|
||||
|
||||
for _, argument := range arguments {
|
||||
@@ -51,9 +52,9 @@ func reduceLet(s *saccharine.LetStatement, e lambda.Expression) lambda.Expressio
|
||||
var value lambda.Expression
|
||||
|
||||
if len(s.Parameters) == 0 {
|
||||
value = SaccharineToLambda(s.Body)
|
||||
value = encodeExpression(s.Body)
|
||||
} else {
|
||||
value = convertAbstraction(saccharine.NewAbstraction(s.Parameters, s.Body))
|
||||
value = encodeAbstraction(saccharine.NewAbstraction(s.Parameters, s.Body))
|
||||
}
|
||||
|
||||
return lambda.NewApplication(
|
||||
@@ -67,7 +68,7 @@ func reduceDeclare(s *saccharine.DeclareStatement, e lambda.Expression) lambda.E
|
||||
|
||||
return lambda.NewApplication(
|
||||
lambda.NewAbstraction(freshVar, e),
|
||||
SaccharineToLambda(s.Value),
|
||||
encodeExpression(s.Value),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -82,8 +83,8 @@ func reduceStatement(s saccharine.Statement, e lambda.Expression) lambda.Express
|
||||
}
|
||||
}
|
||||
|
||||
func convertClause(n *saccharine.Clause) lambda.Expression {
|
||||
result := SaccharineToLambda(n.Returns)
|
||||
func encodeClause(n *saccharine.Clause) lambda.Expression {
|
||||
result := encodeExpression(n.Returns)
|
||||
|
||||
for i := len(n.Statements) - 1; i >= 0; i-- {
|
||||
result = reduceStatement(n.Statements[i], result)
|
||||
@@ -92,17 +93,46 @@ func convertClause(n *saccharine.Clause) lambda.Expression {
|
||||
return result
|
||||
}
|
||||
|
||||
func SaccharineToLambda(n saccharine.Expression) lambda.Expression {
|
||||
switch n := n.(type) {
|
||||
func encodeExpression(s saccharine.Expression) lambda.Expression {
|
||||
switch s := s.(type) {
|
||||
case *saccharine.Atom:
|
||||
return convertAtom(n)
|
||||
return encodeAtom(s)
|
||||
case *saccharine.Abstraction:
|
||||
return convertAbstraction(n)
|
||||
return encodeAbstraction(s)
|
||||
case *saccharine.Application:
|
||||
return convertApplication(n)
|
||||
return encodeApplication(s)
|
||||
case *saccharine.Clause:
|
||||
return convertClause(n)
|
||||
return encodeClause(s)
|
||||
default:
|
||||
panic(fmt.Errorf("unknown expression type: %T", n))
|
||||
panic(fmt.Errorf("unknown expression type: %T", s))
|
||||
}
|
||||
}
|
||||
|
||||
func decodeExression(l lambda.Expression) saccharine.Expression {
|
||||
switch l := l.(type) {
|
||||
case lambda.Variable:
|
||||
return saccharine.NewAtom(l.Name())
|
||||
case lambda.Abstraction:
|
||||
return saccharine.NewAbstraction(
|
||||
[]string{l.Parameter()},
|
||||
decodeExression(l.Body()))
|
||||
case lambda.Application:
|
||||
return saccharine.NewApplication(
|
||||
decodeExression(l.Abstraction()),
|
||||
[]saccharine.Expression{decodeExression(l.Argument())})
|
||||
default:
|
||||
panic(fmt.Errorf("unknown expression type: %T", l))
|
||||
}
|
||||
}
|
||||
|
||||
type Saccharine2Lambda struct{}
|
||||
|
||||
func (c Saccharine2Lambda) Decode(l lambda.Expression) (saccharine.Expression, error) {
|
||||
return decodeExression(l), nil
|
||||
}
|
||||
|
||||
func (c Saccharine2Lambda) Encode(s saccharine.Expression) (lambda.Expression, error) {
|
||||
return encodeExpression(s), nil
|
||||
}
|
||||
|
||||
var _ codec.Codec[saccharine.Expression, lambda.Expression] = (*Saccharine2Lambda)(nil)
|
||||
|
||||
34
pkg/engine/normalorder/engine.go
Normal file
34
pkg/engine/normalorder/engine.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package normalorder
|
||||
|
||||
import (
|
||||
"git.maximhutz.com/max/lambda/pkg/engine"
|
||||
"git.maximhutz.com/max/lambda/pkg/lambda"
|
||||
)
|
||||
|
||||
type Engine struct {
|
||||
expr lambda.Expression
|
||||
}
|
||||
|
||||
func (e Engine) Get() (lambda.Expression, error) {
|
||||
return e.expr, nil
|
||||
}
|
||||
|
||||
func (e Engine) Set(l lambda.Expression) error {
|
||||
e.expr = l
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e Engine) Step(i int) bool {
|
||||
var reduced bool
|
||||
|
||||
for range i {
|
||||
e.expr, reduced = ReduceOnce(e.expr)
|
||||
if !reduced {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var _ engine.Engine[lambda.Expression] = (*Engine)(nil)
|
||||
34
pkg/engine/normalorder/reduce_one.go
Normal file
34
pkg/engine/normalorder/reduce_one.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package normalorder
|
||||
|
||||
import "git.maximhutz.com/max/lambda/pkg/lambda"
|
||||
|
||||
func ReduceOnce(e lambda.Expression) (lambda.Expression, bool) {
|
||||
switch e := e.(type) {
|
||||
case lambda.Abstraction:
|
||||
body, reduced := ReduceOnce(e.Body())
|
||||
if reduced {
|
||||
return lambda.NewAbstraction(e.Parameter(), body), true
|
||||
}
|
||||
return e, false
|
||||
|
||||
case lambda.Application:
|
||||
if fn, fnOk := e.Abstraction().(lambda.Abstraction); fnOk {
|
||||
return fn.Body().Substitute(fn.Parameter(), e.Argument()), true
|
||||
}
|
||||
|
||||
abs, reduced := ReduceOnce(e.Abstraction())
|
||||
if reduced {
|
||||
return lambda.NewApplication(abs, e.Argument()), true
|
||||
}
|
||||
|
||||
arg, reduced := ReduceOnce(e.Argument())
|
||||
if reduced {
|
||||
return lambda.NewApplication(e.Abstraction(), arg), true
|
||||
}
|
||||
|
||||
return e, false
|
||||
|
||||
default:
|
||||
return e, false
|
||||
}
|
||||
}
|
||||
19
pkg/lambda/marshaler.go
Normal file
19
pkg/lambda/marshaler.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package lambda
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.maximhutz.com/max/lambda/pkg/codec"
|
||||
)
|
||||
|
||||
type Marshaler struct{}
|
||||
|
||||
func (m Marshaler) Decode(string) (Expression, error) {
|
||||
return nil, fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
func (m Marshaler) Encode(e Expression) (string, error) {
|
||||
return e.String(), nil
|
||||
}
|
||||
|
||||
var _ codec.Marshaler[Expression] = (*Marshaler)(nil)
|
||||
Reference in New Issue
Block a user