[R6RS] Scripts and toplevel code

dyb at cs.indiana.edu dyb at cs.indiana.edu
Wed Aug 16 17:01:11 EDT 2006

>     #!/usr/bin/[env ]scheme-script <line break> [#!r6rs]
>     (import <import-spec>*)
>     <library body>
>     <library>*

A problem with this, probably fatal, is that the library form becomes a
macro-expanded form or the library keyword has to be reserved.  For
example, it's not clear what to do with the following examples:

  (import r6rs foo bar)
  (define-syntax xlibrary
    (syntax-rules ()
      ((_ stuff ...) (library stuff ...))))
  (xlibrary foo ---)

  (import r6rs)
  (define-syntax library
    (syntax-rules ()
      ((_ stuff ...) (display "oops\n"))))
  (library foo
    (import r6rs)
    (export bar)
    (define bar 3))

Even if we work around this somehow, putting libraries after code that
uses them might be confusing, and it would require that an implementation
defer execution of <library body> until after the libraries have been
invoked.  The order of evaluation can become pretty strange.  E.g., I
assume that

  (import r6rs foo)
  (display-string "first\n")
  (library foo
    (import r6rs)
    (display-string "second\n"))

would print "second" before printing "first".

I favor the even simpler

   #!/usr/bin/[env ]scheme-script <line break> [#!r6rs]
   (import <import-spec>*)
   <library body>

The idea is that the script body is an anonymous library with an implicit
empty export form.

I like this because it is simple and has an obvious semantics that can be
described in terms of expanding and executing a single library, so we
don't have to do much to describe the semantics of script evaluation.

It doesn't go as far toward ensuring the level of debuggability that Mike
wants, but programmers can be encouraged to do all of the work in a main
routine and that the last line of the script be (apply main
(command-line)) if they want to make their scripts more debuggable.

If we go with the simpler syntax, it doesn't preclude more elaborate
proposals for future SRFIs or reports; the required import form just
after the script header can be replaced in the SRFI or future report
with something different, like a (script ---) form.

> 3.2.1 Script Startup
> --------------------
> There are two major choices for specifying how execution of a script 
> should be started:
> (a) By executing top level code (or code at the top level of a library 
> body).
> (b) By executing a particular named procedure, with a name that is either:
>      (i) fixed by the specification, e.g. "main".
>      or
>      (ii) specified in the <script spec>, as in the current proposal.
> For choice (a), a way to access the command line arguments is required, 
> e.g. a procedure named 'command-line'.  For choice (b), command-line 
> arguments can be passed as ordinary arguments to the script entry procedure.

Even with (b), the script can start executing even before "main" is
called.  It just doesn't get its command-line arguments until "main" is

> If a script body is a library, it implies that other scripts and 
> libraries can import it.  This is an advantage for debugging, testing, 
> and other reuse of scripts.

This is true only if we decide it's true.  Personally, I'd rather not
require that implementations treat files containing script headers as
libraries, no matter how they are structured.  It seems like this could
lead to compatibility complications down the road.  The simpler we make
our R6RS libraries, the easier it will be for R7+RS implementations to
handle them.

> If the script body consists of top-level code, it could be specified to 
> support interleaved definitions and expressions, to provide a more 
> relaxed syntax, as mentioned in the rationale.

I prefer not to allow interleaved execution, but I agree that this is an
orthogonal issue.  I want to keep the tie between script bodies and
library bodies as close as possible so that we don't have to do much
work to specify script semantics.


More information about the R6RS mailing list