[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Begin flattening documentation bug (CC)



To: norman@parc.xerox.COM
From: KenD@Newton.apple.com (Ken Dickey)
Subject: BEGIN "flattening" definition bug
Cc: rrrs-authors@ai.mit.edu

Norman,

As you know, I hate to pollute the global namespace and
would like to be able to lexically hide what I consider to
be local names.  This lead me to a problem I mentioned to
you with "begin flattening" which I believe indicates a
deeper problem.


The form that I proposed is:

;;(define-values (name ...)
;;    body-form ...
;;    values-form)

This allows me to write:

(define-values (MAKE-INSTANCE INSTANCE?)
 (let ( (instance-tag "instance") )  ;; unique tag
   (values
    ; make-instance
    (lambda (dispatcher) (cons instance-tag dispatcher))
    ; instance?
    (lambda (obj) (and (pair? obj) (eq? (car obj) instance-tag)))
) ) )


rather than the equivalent:

(define make-instance 'bogus)
(define instance?     'bogus)
(let ( (instance-tag "instance") )
 (set! MAKE-INSTANCE
  (lambda (dispatcher) (cons instance-tag dispatcher)))
 (set! INSTANCE?
  (lambda (obj) (and (pair? obj) (eq? (car obj) instance-tag))))
)


A cheap implementation of this is:

(define-syntax DEFINE-VALUES
 (syntax-rules ()
  ((define-values (<name> ...) <body> ...)
   ; =>
   (define-values helper (<name> ...) () (<name> ...) <body> ...)
  )
  ((define-values helper () (<temp> ...) (<name> ...) <body> ...)
   ; =>
   (begin
     (define <name> #f) ...
     (call-with-values
        (lambda () <body> ...)
        (lambda (<temp> ...)
          (set! <name> <temp>) ...
     )  )
  ))
  ((define-values helper (<var1> <var2> ...) <temp>s
                         (<name> ...) <body> ...)
   ; =>
   (define-values helper (<var2> ...) (<temp> . <temp>s)
                         (<name> ...) <body> ...)
  )
))


Which expands as you expect from the example above.

The problem is that the enclosing (begin ...) form is not
flattened.  This results in the definitions being made in
a local rather than in the global namespace.  [Operationally,
some Scheme implementations do the definitions in a lexically
local namespace, some in the global namespace!]

This is because R4RS (section 5.2) specifies that begin
flattening only occurs with definitions.  I.e.
  (begin <definition>+)
gets flattened, but
  (begin <definition>+ <expression>+)
does not.


It is my opinion that BEGIN is a sequencing construct and
unlike LAMBDA, LET, LET*, and LETREC, should *not*
introduce a new lexical contour.  As it stands, any macro
which introduces definitions and some other computation
will have the above problem.

Any chance that this can be fixed in R^5?  In any case, the
wording should be clarified such that all Scheme
implementations have the same behavior.


Thanks,
-Ken