feat: move lambda reduction to "lambda reduce"

This commit is contained in:
2026-02-05 22:55:33 -05:00
parent b47a3a3acb
commit d21dde40e9
3 changed files with 113 additions and 66 deletions

View File

@@ -4,8 +4,6 @@ import (
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"git.maximhutz.com/max/lambda/internal/config"
) )
func Lambda() *cobra.Command { func Lambda() *cobra.Command {
@@ -14,73 +12,13 @@ func Lambda() *cobra.Command {
Short: "Lambda calculus interpreter", Short: "Lambda calculus interpreter",
Long: "A lambda calculus interpreter supporting multiple representations.", Long: "A lambda calculus interpreter supporting multiple representations.",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
// Legacy behavior when no subcommand is given. return cmd.Help()
options, err := config.FromArgs()
if err != nil {
return err
}
logger := options.GetLogger()
logger.Info("using program arguments", "args", os.Args)
logger.Info("parsed CLI options", "options", options)
r := GetRegistry()
// Get input.
input, err := options.Source.Extract()
if err != nil {
return err
}
// Parse code into syntax tree.
repr, err := r.Unmarshal(input, "saccharine")
if err != nil {
return err
}
logger.Info("parsed syntax tree", "tree", repr)
// Compile expression to lambda calculus.
compiled, err := r.ConvertTo(repr, "lambda")
if err != nil {
return err
}
logger.Info("compiled λ expression", "tree", compiled)
// Create reducer with the compiled expression.
engine, err := r.GetDefaultEngine("lambda")
if err != nil {
return err
}
process := engine.Load()
err = process.Set(compiled)
if err != nil {
return err
}
// Run reduction.
for process.Step(1) {
}
// Return the final reduced result.
result, err := process.Get()
if err != nil {
return err
}
output, err := r.Marshal(result)
if err != nil {
return err
}
return options.Destination.Write(output)
}, },
} }
cmd.Flags().BoolP("verbose", "v", false, "Enable verbose output")
cmd.AddCommand(LambdaConvert()) cmd.AddCommand(LambdaConvert())
cmd.AddCommand(LambdaEngine()) cmd.AddCommand(LambdaEngine())
cmd.AddCommand(LambdaReduce())
return cmd return cmd
} }

View File

@@ -87,8 +87,8 @@ func LambdaConvert() *cobra.Command {
}, },
} }
cmd.Flags().StringVarP(&inputReprFlag, "input", "i", "", "Input representation (inferred from extension if unset)") cmd.Flags().StringVar(&inputReprFlag, "from", "", "Input representation (inferred from extension if unset)")
cmd.Flags().StringVarP(&outputReprFlag, "output", "o", "", "Output representation (inferred from extension if unset)") cmd.Flags().StringVar(&outputReprFlag, "to", "", "Output representation (inferred from extension if unset)")
return cmd return cmd
} }

109
cmd/lambda/lambda_reduce.go Normal file
View File

@@ -0,0 +1,109 @@
package main
import (
"fmt"
"github.com/spf13/cobra"
"git.maximhutz.com/max/lambda/internal/cli"
"git.maximhutz.com/max/lambda/internal/config"
)
func LambdaReduce() *cobra.Command {
var inputReprFlag string
var engineFlag string
cmd := &cobra.Command{
Use: "reduce <input-file>",
Short: "Reduce a lambda calculus expression",
SilenceUsage: true,
Aliases: []string{"run"},
RunE: func(cmd *cobra.Command, args []string) error {
var err error
if len(args) != 1 {
return cmd.Help()
}
inputPath := args[0]
// Get input source.
var source config.Source
if inputPath == "-" {
source = config.StdinSource{}
} else {
source = config.FileSource{Path: inputPath}
}
destination := config.StdoutDestination{}
r := GetRegistry()
// Get input.
input, err := source.Extract()
if err != nil {
return err
}
// Use flag if provided, otherwise infer from extension.
inputRepr := inputReprFlag
if inputRepr == "" {
if inputRepr, err = inferReprFromPath(inputPath); err != nil {
return fmt.Errorf("input file: %w", err)
}
}
// Find engine.
var engine cli.Engine
if engineFlag == "" {
if engine, err = r.GetDefaultEngine(inputRepr); err != nil {
return err
}
} else {
if engine, err = r.GetEngine(engineFlag); err != nil {
return err
}
}
// Parse code into syntax tree.
repr, err := r.Unmarshal(input, inputRepr)
if err != nil {
return err
}
// Compile expression to lambda calculus.
compiled, err := r.ConvertTo(repr, "lambda")
if err != nil {
return err
}
// Create process.
process := engine.Load()
err = process.Set(compiled)
if err != nil {
return err
}
// Run reduction.
for process.Step(1) {
}
// Return the final reduced result.
result, err := process.Get()
if err != nil {
return err
}
output, err := r.Marshal(result)
if err != nil {
return err
}
return destination.Write(output)
},
}
cmd.Flags().StringVar(&inputReprFlag, "from", "", "Input representation (inferred from extension if unset)")
cmd.Flags().StringVarP(&engineFlag, "engine", "e", "", "Reduction engine (inferred from '--input' if unset)")
return cmd
}