[R6RS] Goals

R. Kent Dybvig dyb
Sun Jan 25 22:55:44 EST 2004


Thanks for getting the ball rolling.  I've been thinking about my list,
but haven't written it down yet.  Below are some comments on a few
selected items from your list.  (Nothing should be read into the fact
that I haven't commented on the many other items.)

I suggest that we start building a secure (password protected) web page
with itemized lists (with subitems where appropriate) of proposed language
additions, deletions, and modifications.  We can start with your list,
add to it, modify it, or subtract from it (or maybe just record arguments
against) ones we decide not to do.  Maybe what I'm really looking for is
an outline of R6RS.  If someone knows how to set up a secure CVS site,
that might be a good way to go.



>     3.5) Remove multiple values.  Their usefulness is questionable
>          when record types are available, and the syntax to use them
>          is clumsy (I find that for the code I write explicit CPS is
>          more readable and flexible!).

I disagree.  I've found multiple values very useful, and with let-values,
not at all clumsy.  I find my code that uses multiple values to be much
clearer than code that uses other available mechanisms.  They are also
handy as an intermediate target for domain-specific languages implemented
via syntactic abstraction, where converting to cps may be difficult.

>     6.2) Add optional and keyword parameters, as specified by the
>          DSSSL standard.  Keyword parameters are particularly useful
>          when a procedure has many optional parameters.  The semantics
>          should be fairly obvious from this example:

I prefer case-lambda to the #!optional syntax.  It's more general in
two ways: (1) one can easily create procedures that take, say, either
one or three arguments but not two, and (2) one doesn't have to think
up or test for a default value in cases where one intends to do two
different things depending upon the number of arguments.  Both are
fairly common circumstances, at least for us since we have a mechanism
for supporting them.

>     7.6) Uninterned symbols: #:g0 .

Chez Scheme no longer supports simple uninterned symbols or the #:
prefix, and I'd prefer to standardize on the generated symbol model it
currently supports.  (More on this below.)

> 12) Continuations.

>     Define a type for continuations that is separate from procedures,
>     and operations to capture and invoke continuations of this type.
>     For example: continuation-capture, continuation-call, and
>     continuation-return.  The procedure call-with-current-continuation
>     can be defined in terms of this type for backward compatibility.

I don't know of any justification for doing this.  If we're going to
mess with continuations, however, I'd like to go with a base set of
operators that supports both call/cc and composable continuations.

> 17) Boxes.

>     Add the box type.

I prefer to leave boxes out.  It's no big deal to use pairs and put
something innocuous in the cdr field, and with a record-definition
facility, one can always define a single-celled record type if desired.

> 18) Uninterned symbols.

>     Add the procedures gensym, string->uninterned-symbol and
>     uninterned-symbol?.

I prefer to adopt Chez Scheme's globally unique symbols.  Here's how
they work, in brief: (gensym) returns a generated symbol.  (gensym? x)
returns true for generated symbols, false for everything else.
(symbol? (gensym)) is also true.  gensym's have a generated "pretty"
name, which you get from symbol->string, that looks like g0, g1, g2,
etc.  You can also invoke gensym as (gensym <string>) in which case
the pretty name is <string>. They also have a generated "unique" name,
which is globally unique (constructed from, e.g., MAC address, process
id, process start-up time, and sequence number) and is thus unique even
across separate compiles, including parallel makes on the same machine.
(display (gensym)) prints the pretty name, while (write (gensym))
prints both names using the syntax #{<pretty-name> <unique-name>}.
For efficiency, an implementation need not construct either of the
generated names until requested.  Also for efficiency, an implementation
need not intern a gensym until it gets a unique name.

We use globally unique symbols for at least two purposes in Chez Scheme:
as record-type names so that we can uniquely identify the type in the
printed syntax and compiled representation and for names of generated
identifiers in the macro expanders, particularly global names.  In both
cases, the unique names support separate compilation and linking.
For example, consider

  (define-syntax alpha
    (syntax-rules ()
      ((_ x)
         (define t 0)
         (define-syntax x (identifier-syntax (begin (set! t (+ t 1)) t)))))))

in which t is global but visible only to x, so that

  (alpha a++)

expands to a definition of a hidden generated name for t and a syntax
definition of a++ that expands references to a++ into an expression
involving the hidden generated name for t.  The globally unique name
generated for t allows us to include references to a++ in separately
compiled files without difficulty.

Globally unique names serve a similar purpose for compiled record
definitions and also allow one to specify nongenerative record types
by using a gensym for the record name, e.g., in Chez Scheme

  (define-record foo ---) 

is compile-time generative, i.e., a new record type (with new unique
[gensym] name) is created each time the definition is compiled, and

  (define-record #{foo |+hvRriLCcPV4l\\%|} ---)  ; nongenerative

is nongenerative.  In the latter case, a new record type may be allocated,
but always with the unique name specified.  If two incompatible record
types with the same unique name are ever defined or loaded into the same
system, an error is signaled.  This allows us include copies of the same
record definition in two or more separately compiled files.

More information about the R6RS mailing list