shap@POLYA.STANFORD.EDU (Jonathan S. Shapiro) (04/16/89)
I recently grabbed a copy of the standard dated April 15 from zurich.ai.mit.edu. I am forwarding some comments that I think are relevant for R4RS to this group too. Since I am new to the scheme community, it would be presumptuous to assume that I have understood the subtleties of all of the standard, but there are some areas that were unclear to me or seemed to permit contradictory interpretations, and I thought I would send out comments on these areas. I hope the scheme group will accept those comments that are helpful, and I look forward to any feedback I may get on my misunderstandings. DEFINE: The semantics of DEFINE is historically problematic. The change in R3RS that eliminated the implicit LETREC in defines forces me to generate code that checks to see if the procedure's variable has been side effected by someone I call before I do the tail-recursive call. If there were no other way to achieve side-effectability I would be content with this, but it seems to me that there is an alternative that does not require the compiler to pessimize the most-common-case: First, I suggest that including (define <variable>) in R4RS, and specifying that <variable> gets bound to an unspecified value addresses the needs of both compilers and users. If this change is made (I am sending this proposal to the scheme-standard group too on the grounds that usage has effectively standardized it), then the common case can be rewritten as: (define name => (begin (define name) (lambda ...)) (set! name (letrec ((name (lambda ...))) name))) and the less-common case is still handled when needed by explicitly writing the sequence (define name) (set! name (lambda ...)) Whatever is done, the semantics of what scope the lambda appears in should be specified. The only real problem I see with this is that it may imply a need to extend BEGIN to handle things like (begin (define ...) (set! ...) (define ...)) WRITE: Write should return #f on failure and #t on success, or it should be an error to write a value to an external port that lacks an external representation. I advocate returning #t or #f, which would permit me to build a wrapper function to deal with failure rationally, and avoids the need to define external ports. Failing to distinguish external ports from internal ports is a bad idea because it constrains an implementation from defining something analogous to a pipe. Returning #t or #f lets the program deal with write errors by attempting to tell someone. This would also permit an implementation to extend write such that it can write continuations, and thereby implement DUMP-HEAP. Programs could assume this facility, try it, and issue an appropriate diagnostic if it doesn't work. The standard shouldn't include DUMP-HEAP, but it shouldn't constrain WRITE in a way that prohibits it either. GENERAL: 1) Implementations should be encouraged somewhere to implement (WRITE <continuation>). A representation should be written that when read with READ results in a thunk that is an equivalent function to the written continuation. The representation of continuations should be implementation-defined. Rationale: We all acknowledge that this is pragmatically something that we want, and there should be a standard interface. Having write return a value lets me assume the capability without causing problems for implementations that don't support it. 2) I believe that the user-interface section should specify a procedure (DUMP-WORLD "filename" <continuation>) that writes a representation that can be executed in an implementation-dependent way to arrive at the specified continuation. The <continuation> argument should be optional, and if left unspecified should default to the continuation that DUMP-WORLD will return to. DUMP-WORLD should return #t if it succeeds or #f if it fails or the implementation doesn't supply the functionality. Rationale: The whole community acknowledges that we want this, but that it is implementation-dependent. This proposal permits us to specify the interface to it and construct our programs in a way that deals gracefully with failure and doesn't impose it on implmementations that don't or can't do it. Why DUMP-WORLD and not DUMP-HEAP? Unlike DUMP-HEAP, which is covered by WRITE, DUMP-WORLD does something fundamentally implementation-specific.