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 encodeAtom(n *saccharine.Atom) lambda.Expression { return lambda.NewVariable(n.Name) } func encodeAbstraction(n *saccharine.Abstraction) lambda.Expression { result := encodeExpression(n.Body) parameters := n.Parameters // If the function has no parameters, it is a thunk. Lambda calculus still // requires _some_ parameter exists, so generate one. if len(parameters) == 0 { freeVars := result.GetFree() freshName := lambda.GenerateFreshName(freeVars) parameters = append(parameters, freshName) } for i := len(parameters) - 1; i >= 0; i-- { result = lambda.NewAbstraction(parameters[i], result) } return result } func encodeApplication(n *saccharine.Application) lambda.Expression { result := encodeExpression(n.Abstraction) arguments := []lambda.Expression{} for _, argument := range n.Arguments { encodeedArgument := encodeExpression(argument) arguments = append(arguments, encodeedArgument) } for _, argument := range arguments { result = lambda.NewApplication(result, argument) } return result } func reduceLet(s *saccharine.LetStatement, e lambda.Expression) lambda.Expression { var value lambda.Expression if len(s.Parameters) == 0 { value = encodeExpression(s.Body) } else { value = encodeAbstraction(saccharine.NewAbstraction(s.Parameters, s.Body)) } return lambda.NewApplication( lambda.NewAbstraction(s.Name, e), value, ) } func reduceDeclare(s *saccharine.DeclareStatement, e lambda.Expression) lambda.Expression { freshVar := lambda.GenerateFreshName(e.GetFree()) return lambda.NewApplication( lambda.NewAbstraction(freshVar, e), encodeExpression(s.Value), ) } func reduceStatement(s saccharine.Statement, e lambda.Expression) lambda.Expression { switch s := s.(type) { case *saccharine.DeclareStatement: return reduceDeclare(s, e) case *saccharine.LetStatement: return reduceLet(s, e) default: panic(fmt.Errorf("unknown statement type: %v", s)) } } 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) } return result } func encodeExpression(s saccharine.Expression) lambda.Expression { switch s := s.(type) { case *saccharine.Atom: return encodeAtom(s) case *saccharine.Abstraction: return encodeAbstraction(s) case *saccharine.Application: return encodeApplication(s) case *saccharine.Clause: return encodeClause(s) default: 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)