// Package convert defined some standard conversions between various types of // representations. package convert import ( "fmt" "git.maximhutz.com/max/lambda/pkg/lambda" "git.maximhutz.com/max/lambda/pkg/saccharine" ) func encodeAtom(n *saccharine.Atom) lambda.Expression { return lambda.Variable{Name: 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 := lambda.GetFree(result) freshName := lambda.GenerateFreshName(freeVars) parameters = append(parameters, freshName) } for i := len(parameters) - 1; i >= 0; i-- { result = lambda.Abstraction{Parameter: parameters[i], Body: 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.Application{Abstraction: result, Argument: 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.Abstraction{Parameters: s.Parameters, Body: s.Body}) } return lambda.Application{ Abstraction: lambda.Abstraction{Parameter: s.Name, Body: e}, Argument: value, } } func reduceDeclare(s *saccharine.DeclareStatement, e lambda.Expression) lambda.Expression { freshVar := lambda.GenerateFreshName(lambda.GetFree(e)) return lambda.Application{ Abstraction: lambda.Abstraction{Parameter: freshVar, Body: e}, Argument: 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.Atom{Name: l.Name} case lambda.Abstraction: return &saccharine.Abstraction{ Parameters: []string{l.Parameter}, Body: decodeExression(l.Body)} case lambda.Application: return &saccharine.Application{ Abstraction: decodeExression(l.Abstraction), Arguments: []saccharine.Expression{decodeExression(l.Argument)}} default: panic(fmt.Errorf("unknown expression type: %T", l)) } } // Lambda2Saccharine converts a pure lambda calculus expression into its // Saccharine counterpart. func Lambda2Saccharine(l lambda.Expression) (saccharine.Expression, error) { return decodeExression(l), nil } // Saccharine2Lambda desugars a saccharine expression into pure lambda calculus. func Saccharine2Lambda(s saccharine.Expression) (lambda.Expression, error) { return encodeExpression(s), nil }