larcenists / larceny

Larceny Scheme implementation
Other
202 stars 32 forks source link

Larceny's let(rec)-syntax violates the R7RS spec #807

Closed mnieper closed 7 years ago

mnieper commented 7 years ago

By the R6RS. the expression

(let ((x 'r7rs))
  (let-syntax () (define x 'r6rs) #f)
  x)

should evaluate to r6rs. By the R7RS, it should evaluate to r7rs.

The let(rec)-syntax forms of the R6RS and the R7RS are fundamentally incompatible because the R6RS version splices the body of let-syntax into the outer scope, while the R7RS version creates an inner scope.

Larceny's let-syntax, even if imported from (scheme base), just follows the R6RS semantics. This is not a minor issue because it really breaks code (the sample implementation of SRFI 148 written in portable R7RS does not work for Larceny, for example).

I agree that the R6RS version is more powerful (although incompatible with the R5RS version, which has the R7RS semantics), but the R7RS returned to the R5RS version. Hopefully, we will see a let(rec)-syntax/splicing in R7RS-large, which is all what we could get because changing letrec-syntax in R7RS-large would make it fundamentally incompatible with the R7RS.

(So, initially I was quite fond of Larceny's success to weave (scheme base) and (rnrs base) together and to which the current specification of SRFI 149 - see our discussion there - would have been an obstacle. But now it appears to me that this goal is simply not possible without making great compromises to make the bindings in (scheme base) and (rnrs base) compatible, thus making our discussion on SRFI 149 less an issue.)

WillClinger commented 7 years ago

To make it possible for R6RS and R7RS code to interoperate well, compromises are necessary. Had WG1 given more weight to backward compatibility with R6RS, fewer compromises would have been necessary, and R7RS (small) would have described a better programming language.

mnieper commented 7 years ago

I think we cannot blaim WG1 here because in its charter it says: "The language should be mostly compatible, and comparable in size, with R5RS." and "Insofar as practical, the language should be backwards compatible with the IEEE standard, the R5RS standard, and an appropriate subset of the R6RS standard." It was R6RS that changed the semantics of let(rec)-syntax, so WG1 had to make a choice between backwards compatibility with the R5RS or the R6RS.

WG1 explicitly says here that the choice was made to preserve backward compatibility: http://trac.sacrideo.us/wg/wiki/FiveToSixToSeven. Its members voted quite unanimously on the topic: http://trac.sacrideo.us/wg/wiki/WG1Ballot2Results#a48let-syntax.

Larceny should mention its incompatibility with the R7RS on the page https://github.com/larcenists/larceny/wiki/DeprecatedR7RSSyntaxAndProcedures so that users won't be surprised.

In the long run, I hope that Larceny gets a true R7RS mode, in which (scheme base) follows the R7RS semantics strictly. (In such a mode, the library (larceny r7r6) that makes the necessary compromises for R6RS compatibility, could still be available; in such a mode, a user would just have to take care by themselves that imports from (scheme base) and (larceny r7r6) into the same library may need prefixing or renaming.)

Implementing such a "true R7RS mode" could possibly be as simply as locating the R7RS standard libraries in another path.

WillClinger commented 7 years ago

I have changed Larceny's implementation of SRFI 147 so it provides the deprecated behavior for let-syntax and letrec-syntax. The sample implementation of SRFI 148 still doesn't work, even though it imports SRFI 147 instead of relying on Larceny's native let-syntax and letrec-syntax, so I believe the problem with the sample implementation of SRFI 148 lies elsewhere.

As for WG1's decision, their rationale says the R6RS semantics was "Rejected for backward compatibility with existing Schemes." If the WG1 decision had really preserved backward compatibility with existing Schemes, it would have preserved backward compatibility with Larceny and Sagittarius, which it did not. By preserving backward compatibility with the existing implementation of Scheme known as Larceny, Larceny actually accomplishes the backward compatibility falsely claimed by the R7RS rationale for this decision.

mnieper commented 7 years ago

Will Clinger notifications@github.com schrieb am Di., 18. Juli 2017 um 15:06 Uhr:

I have changed Larceny's implementation of SRFI 147 so it provides the deprecated behavior for let-syntax and letrec-syntax. The sample implementation of SRFI 148 still doesn't work, even though it imports SRFI 147 instead of relying on Larceny's native let-syntax and letrec-syntax, so I believe the problem with the sample implementation of SRFI 148 lies elsewhere.

I will investigate the sample implementation of SRFI 148. I have developed and tested it with Chibi. Expansion of the SRFI 148 sample implementation is very slow in Larceny (I would have guessed that it would be much faster than Chibi's interpreter), but this is hopefully a minor problem because of Larceny's precompilation feature.

As for WG1's decision, their rationale says the R6RS semantics was "Rejected for backward compatibility with existing Schemes." If the WG1 decision had really preserved backward compatibility with existing Schemes, it would have preserved backward compatibility with Larceny and Sagittarius, which it did not.

I think WG1 meant to preserve backward compatibility with existing R5RS Schemes, like Scheme48 or Gambit.

(NB: In its R7RS mode, Sagittarius supports the R7RS semantics; but this, of course, was implemented after R7RS had been finished.)

WillClinger commented 7 years ago

Changeset 61b19a06e3202a1e47a7ae31d935304d0ae8177b added an -r7strict mode that forces let-syntax and letrec-syntax to introduce a new contour instead of conforming to R6RS semantics. That mode also disables R6RS lexical syntax and possibly a few other extensions.

As it turns out, the R7RS (small) standard does not actually forbid the R6RS semantics for let-syntax and letrec-syntax. As Marc pointed out, however, the WG1 archives reveal a clear decision to break backward compatibility, so the R7RS's silence on this subject must have been an editorial oversight.

The R7RS (small) document was ratified by the Scheme community and accepted by the Scheme Language Steering Committee, but those actions concern the R7RS (small) standard as written, and do not imply approval of votes recorded in WG1 archives that somehow failed to make their way into the document.

I have therefore re-classified this issue as a matter of "enhancement" rather than "correctness".