Command Line Subcommands in Scheme

Here’s the translation of the Go code to Scheme, formatted in Markdown suitable for Hugo:

Our first example demonstrates how to implement command-line subcommands in Scheme. This is similar to how tools like git have multiple subcommands, each with its own set of flags.

(import (scheme base)
        (scheme process-context)
        (scheme write))

(define (parse-args args)
  (let ((subcommand (if (null? args) "" (car args)))
        (rest-args (if (null? args) '() (cdr args))))
    (case subcommand
      (("foo")
       (let-values (((enable name rest) (parse-foo-args rest-args)))
         (display "subcommand 'foo'\n")
         (display "  enable: ") (display enable) (newline)
         (display "  name: ") (display name) (newline)
         (display "  tail: ") (display rest) (newline)))
      (("bar")
       (let-values (((level rest) (parse-bar-args rest-args)))
         (display "subcommand 'bar'\n")
         (display "  level: ") (display level) (newline)
         (display "  tail: ") (display rest) (newline)))
      (else
       (display "expected 'foo' or 'bar' subcommands\n")
       (exit 1)))))

(define (parse-foo-args args)
  (let loop ((args args) (enable #f) (name "") (rest '()))
    (if (null? args)
        (values enable name rest)
        (let ((arg (car args)))
          (cond
           ((string=? arg "--enable") (loop (cdr args) #t name rest))
           ((string-prefix? arg "--name=")
            (loop (cdr args) enable (substring arg 7) rest))
           (else (loop (cdr args) enable name (cons arg rest))))))))

(define (parse-bar-args args)
  (let loop ((args args) (level 0) (rest '()))
    (if (null? args)
        (values level rest)
        (let ((arg (car args)))
          (cond
           ((string-prefix? arg "--level=")
            (loop (cdr args) (string->number (substring arg 8)) rest))
           (else (loop (cdr args) level (cons arg rest))))))))

(parse-args (cdr (command-line)))

This Scheme program implements a basic command-line subcommand structure. Here’s how it works:

  1. We define a main parse-args function that handles the subcommands.

  2. For each subcommand (foo and bar), we define separate parsing functions (parse-foo-args and parse-bar-args).

  3. The parse-args function checks the first argument to determine which subcommand to run.

  4. Each subcommand parser function processes its specific flags and arguments.

To run this program, save it to a file (e.g., subcommands.scm) and use your Scheme interpreter. Here are some example invocations:

$ scheme --script subcommands.scm foo --enable --name=joe a1 a2
subcommand 'foo'
  enable: #t
  name: joe
  tail: (a2 a1)

$ scheme --script subcommands.scm bar --level=8 a1
subcommand 'bar'
  level: 8
  tail: (a1)

$ scheme --script subcommands.scm baz
expected 'foo' or 'bar' subcommands

Note that Scheme doesn’t have built-in command-line argument parsing libraries like Go’s flag package, so we’ve implemented a simple parsing mechanism. In a real-world scenario, you might want to use a more robust command-line parsing library for Scheme if available.