Hacker News new | past | comments | ask | show | jobs | submit login
R7RS versus R6RS (2018) (weinholt.se)
131 points by fanf2 on Jan 11, 2020 | hide | past | favorite | 49 comments



I seldom saw such an incredibly weak argumentation as in section "The number argument". Yes, If someone wants Scheme to remain an academic toy language, this might make sense.

I followed the discussion and schisma which resulted in Racket for good. If you want to have a sane language, some pages of specification and rationalization are required, as has been done for R6RS.

If the professors fear that students will no longer be able to implement their Scheme interpreter in a term because the spec has become to complicated please call the language somehow different and stop to encumber the development of an otherwise great language!


There is definitely a split between the people who think it's interesting to program in Scheme and the people who think it's interesting to program <i>a</i> Scheme (particularly to do so in Scheme itself). For the second group, the Scheme language is more of an aesthetic object than a programming language.

The length argument is also a stand-in for the argument about Common Lisp versus Scheme. CL is pretty carefully defined, so the CL spec is pretty long, and some Schemers used this as an argument against CL (that it was bloated). Now suddenly the Scheme spec was also long, so that argument was gone.


It really all depends on what one wants. If one wants an excellent academic exercise, Scheme is pretty great. If one wants an excellent industrial language, Common Lisp is right there.

I am sympathetic to R6RS because it tries to make Scheme more useful for real programming — but in that case why not just use Common Lisp, which is even more useful for that purpose?


I’m not convinced CL is more useful for real world usage. People sometimes fall into the trap of thinking that more features are always better. With programming languages, that’s rarely true, because even features you don’t use cost you something — in terms of training new programmers, and every time your dealing with other people’s code. (And note here that in real-world projects, most of the code you have to modify and debug isn’t yours!)

Of course it’s possible to go too far the other way, and R5RS leaves too many questions unanswered. But in my opinion, simplicity is also an important feature, not just academically, but in practice.


Since one doesn't program in R5RS (a language definition document), but with real implementations, those tend to add quite a bit to Scheme to make practical programming possible.

Example:

https://www.gnu.org/software/mit-scheme/documentation/mit-sc...


Sure, but the point of a standard is usually to make implementations interchangeable.


With all due respect to the author, I followed the r7rs standardization closely, and disagree with his bottom lines.

1. On the number argument: Even the author acknoweldges that R6RS is twice as large. Regardless of the fact that the standard library is the other half, the fact is that the standard library is a requirement for R6RS. Because of the controversies about it (the condition system, record system, hash table library), the R7RS standard was purposely split into 2 parts, the R7RS-small and the R7RS-large. The R7RS-large standardization is an ongoing project.

2. On the condition system: The fact is that horse already left the barn. Most major implementations already had their own condition hierarchies. The only way to reconcile their existing conditions would be to have a translation layer which would be inefficent. Conforming to R6RS condition system would mean throwing out most of the code that people who use those implementations depend on. R7RS focused on providing a basic error system with a purely procedural interface, which combined with cond-expand and the library system, can allow people to write portable code. So the idea that the standard committee doesn't believe "Safety is not a desirable language feature" is unwarrented.

3. On Optional is better argument: Sure you can have an R6RS with restrictions, but then it isn't R6RS, it is a R6RS-like scheme. Using feature identifiers is at least a better way to create portable code. If you have a library that requires unicode, you can specify that in the code.

4. On syntax-case, one of the costs of having it is a more complicated library system, with import and export levels. Read it yourself, http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-10.html#node_se... . R7RS-small decided to be more conservative in this area.

Overall, I think that the way that R7RS standardization has worked to evolve the standard was the right approach. They focused on the most important needs for scheme ( The library system, a basic record system, basic error handling) while avoiding adding features that were overly controversial.


I thought that the whole point of Scheme is for it to be easy to implement. R7RS seems more aligned with Scheme's vision.


I mean originally it was just an exploratory language, something small enough that Steele and crew could keep it all in their head but with lisp flexibility so they didn't have to re-write it everytime they thought up something new.

As far as I know it was never meant to be like a tool to teach compiler/interpreter writing or anything.

That said a big part of R6 which is mentioned in article is that code was not very portable between R5s (N.B. it wasn't much more portable between R6s) and in some sense if your implementation can't run anyone else's code, what have you actually implemented? Something that looks like scheme is easy implement to be sure but I think R6 was trying to make it so that 'scheme' was a language and not an aesthetic.


Ease of implementation leads to a maze of twisty little implementations, all different. It also leads to unaccounted-for corner cases (see: why C is deprecated). The major implementations, Guile and Racket, both embraced R6RS.


Guile has not embraced R6RS:

> R6RS significantly expands the core Scheme language, and standardisesmany non-core functions that implementations—including Guile—have previously done indifferent ways. Guile has been updated to incorporate some of the features of R6RS, and toadjust some existing features to conform to the R6RS specification, but it is by no meansa complete R6RS implementation. SeeSection 7.6

https://www.gnu.org/software/guile/manual/guile.pdf

Neither has Racket, they aren't even calling themselves a scheme any more.



The upcoming 3.0 release has an r6rs mode that makes r6rs easier to use. The r6rs incompatibilities are, apart from (rnrs io ports) and the condition system rather small.

The incompatibilities can be found here: https://www.gnu.org/software/guile/docs/master/guile.html/R6...


Are there any complete implementations of R6RS?


I think Chez is pretty much compliant.


Racket also has a #!lang r6rs.


Chez Scheme.


Stands off to the side waving R4RS flag.


You are not alone! S9fES is still R4RS. :) https://www.t3x.org/s9fes/index.html


I can't not explain why but I always have found the document more easy to read and the hygiene macros steal all the fun from lisp.


I think this is a really fair summary of the technical differences between the two standards written from the perspective of a person who favors R6RS. I especially agree with the point regarding error signalling and the lack of effective facilities for that in R7RS.

I should also say that my perspective is that of an outsider, a user, not someone who is involved in implementing scheme, or in the standards process. With that said, I feel like this post does not capture the social context of R7RS vs R6RS and without that you can't really understand the overall picture.

Scheme has been around for decades and there are probably dozens of implementations. Almost every one of them supported R5RS. Unfortunately this standard didn't specify enough to allow for easy interoperability of scheme programs between implementations, depending on what you were trying to do. So everyone ended up just picking their own scheme and running with it.

R6RS tried to offer enough of a standard to allow for interoperability between implementations, particularly in offering a module/library syntax, and a bunch of the other things listed in the post. The main problem, and really the one that triggered R7RS, was that it was a large enough standard and required enough work that not many implementations updated to conform to it. The standard was ratified in 2007 and when I was looking around for conformant implementations I didn't find a lot. There was Ypsilon scheme, which has since become abandonware. Ikarus scheme by Abulaziz Ghoulum was super fast but was also abandoned. Larceny scheme was compliant I believe but I didn't use it much. Kawa scheme worked to get there but was still not conformant by 2012. Guile never fully implemented it. PLT Scheme implemented it, but 2 years after was already making announcements about leaving Scheme behind and became Racket in 2010. MIT Scheme of SICP fame basically said they'd never implement it. The crown jewel was probably Chez Scheme, still to this day one of the best language implementations period. But it was proprietary in 2007 and cost money. You could use the interpreter based implementation Petite Chez Scheme, but it still had other restrictions I believe. Committing to R6RS as the standard going forward meant abandoning most of the existent implementations, and thus most of the body of code people had written for them. In trying to unify the Scheme world going forward, R6RS was potentially asking for a large schism. Please note that the previous sentence isn't a value judgement. Maybe Scheme would be in a better place given the technical merits of R6RS. I can't deny that. But that is how the world looked (in my view) when R6RS was the scheme standard of the day.

In comparison after R7RS was ratified, many implementations worked to be conformant. Guile is close, Kawa is conformant, Gauche Scheme implements R7RS, Ypsilon is another, Chibi Scheme, Larceny, etc, etc. In terms of standards adoption there's no contest.

Writing this post from 2020, where Chez Scheme is open sourced and free, Akku scheme is a great implementation of R6RS, and we are starting to get package repos for Scheme, maybe R6RS would have been the better choice. Maybe all those other implementations should have fallen by the wayside and we'd all use Chez Scheme, much like CPython is the canonical Python (except Chez Scheme is incredibly well implemented). But at the time the decision was made to make a new standard, a very explicit decision was made to abandon the "easy for users, hard for implementers" motto of R6RS, because what is a language standard without implementations?

My hope is that ongoing work can build on R7RS and get us to the level of excellence and ability to build things that R6RS gave, and maybe we can end up having our cake and eating it to.


I was struggling to find a concise summary of the debate between R7RS vs R6RS earlier this year. This article was the best I found to that end.


last year


[flagged]


RnRS are guidelines like Posix. They aren't implementations.

Systemd is an implementation, not a guideline.

The complaints against systemd are that you will need to be bit-compatible with it when it inevitably fails, which will be soon with what IBM does to the companies it eats.

The complaints against R6RS is that scheme is a simple language, if you want a complex language use Common Lisp instead.


Wait, what really ? JavaScript evolved from scheme ?


No. It's a joke.

See also: how perl8.com used to redirect to scala.com


No, see https://www.youtube.com/watch?v=aX3ZABCdC38 (first few minutes).


No. It’s a meme that has almost no technical grounds.


Brendan Eich was originally going to embed Scheme into Netscape. But higher-ups said no, it has to be familiar and resemble popular languages like Java to get any traction. (They were right.) So Eich went in and threw something together over a few days, and boom -- JavaScript.

JavaScript isn't Scheme, but it's close enough for most programmers working in the real world. (There's even a JavaScript version of SICP.) And while Hackernews rubs one out to Lisp Machine porn, our computers are slowly turning into JavaScript Machines.


> while Hackernews rubs one out

That's gross. Please don't do that here.


>Before I convince you that it’s crazy, let’s step back a bit and ask why would JS adherents make a statement like this to begin with? You don’t hear people saying, “Yeah, FORTRAN is basically Icon” or “Sather has a really solid SNOBOL core,” do you? Why this arbitrary pairing? After meticulous scientific research, I’ve discovered two historical reasons and one weird psychological one.

[...]

>In some weird organic process, the pantheon of programming languages have ordered themselves in terms of prestige. It’s as random but undeniable as music and fashion. Radiohead is on one end, and Nickelback is on the other. No one knows precisely how they got there, but there they are.

>On the Radiohead end, you’ve got Common Lisp, Scheme, Smalltalk, and a few others. Scheme is even more Lisp than Lisp, so it’s like that weird avant garde band no one’s heard of that Radiohead always claims inspired their latest album. If Lisp is Radiohead, Scheme is Kraftwerk.

https://journal.stuffwithstuff.com/2013/07/18/javascript-isn...


I love Kraftwerk! Maybe I should try Scheme?


For what it's worth it, I absolutely love Kraftwerk but, having coded in Scheme for about a decade, I very much dislike Scheme. I'd take Haskell, C++, or Java over Scheme without hesitation. I feel that my life is too short to code in languages without static type checks.


I would say that if your only problem with Scheme is the lack of static typing, as opposed to the litany of other complaints that are popular, then Typed Racket is a serviceable language. I would say it’s type system is at least equal what you get in C++ or Java. It is not as expressive as Haskell (but really what is that doesn’t go full Idris/Agda/ATS), but there are some #langs making headway to that space.


Yes, a static type system at least strong enough to support parametric polymorphism is an unmitigated win. JavaScript sucks in the same way Scheme does in this regard; but thankfully, there's TypeScript.


Try ReasonML


> (They were right.)

I remember at first no one took js seriously. It was only after people started to realize that web pages were an incredibly compelling app-platform that that befan to change.

So I think if Brendan had gone with Scheme, Scheme would be taking over the world like js is now.

Basically, platforms make languages popular, not the other way around.


The risk for this would be that a Schemescript would maybe me less universal had other browser decided to adopt a more java-like language instead


Are there any other features in common other than closures and first class functions? I'm not sure that makes Javascript closer to Scheme than any other language like Python (which also has a version of SICP).


Well, lambdas can be multiline in JavaScript. At a higher level, JavaScript has Scheme's desirable "small language kernel" property.

But ultimately, closures, first-class functions, and lexical scope are all anybody really cares about. The bits that set Scheme apart are tail-call optimization, hygienic macros, and first-class continuations.

* Tail-call optimization fucks with your ability to have correct stack traces when an exception is thrown. You know, exceptions -- those things the Scheme implementor community didn't give much thought to until R6RS. Anyways, not having correct stack traces is a HUGE no-no in production code, which is why the JVM doesn't do TCO and never will.

* Hygienic macros -- Common Lispers are snickering right now. As the article said, syntax-rules is tricky enough to implement without all the added shit syntax-case adds. They both are much more difficult to use than CL's DEFMACRO, and for what? To prevent a class of beginner-tier mistakes that are easily worked around with gensyms. And anyway, JavaScript programmers are one 'npm install' away from Babel or any number of other frameworks that parse, emit, or transform JavaScript ASTs, so so much for Lisp's killer feature in general.

* Continuations -- you're fucking kidding me, right? Continuations are to programs what time travel is to stories: the implications of adding them will blow your brain, so if you're smart you won't use them.


I think it’s worth pointing out a few exceptions to what are decent critiques. As an aside, I agree that these three capabilities, along with first-class functions are essentially the commonly bullet pointed marketing keys for Scheme.

TCO -> I see your point about stack tracing and tend to agree, but more importantly, one key difference between Javascript and Scheme is the focus on recursion. Javascript decided that imperative looping was the proper, idiomatic way to handle iterative expression construction. With this design decision, leaving aside whether the looping vs recursion is an equal trade, TCO was not going to be a priority and the style of programming grew around that first choice or iterative style.

Hygienic Macros - I love macros. However, in contrast to your position, I like my macros like I like my martinis... clean, as a general rule. So while I like a basic assumption of hygienic macros I also want the capability to produce ugly dirty procedural macros to be available. But that is just a preference of mine. I agree that the wealth of options for automated and principled syntax tree manipulation and code generation makes the need for built in macros almost non-existent.

Continuations -> while I understand the strong warning, drifted continuations enable some very nice coding possibilities, particularly implementations of generators, coroutines generally, and better callback syntax. Javascript just decided that instead of handing devs the keys to the Delorean they would just chauffeur everyone, i.e. they built constructs for these common and useful patterns directly into the language semantics. This is particularly the case for future based coroutines, now with the async/await sugar.


> Anyways, not having correct stack traces is a HUGE no-no in production code

I think that’s misleading.

Not having a comprehensive stack trace is much more painful for imperative or especially OO code, where the state at the time of failure is practically impossible to discern.

Erlang gets away with it (for decidedly non-trivial production code like much of the world’s cellular routing) because state is much easier to determine.

(Or maybe I’m blowing smoke. Certainly that’s how it feels to me.)


Tail-call optimization fucks with your ability to have correct stack traces when an exception is thrown.

Safari/JScore, the only browser to implement TCO solved this using shadow stacks.


TCO is a great feature if you want to compile to a language. Recursion is the mother of all loops. TCO really only applies if you have things tail called, and long string of optimizable tail calls are rare.

I have debugged poorly written defmacros for longer time than I spent fighting macro hygiene. I implemented defmacro using syntax rules (about 7 lines of code if you have access to schemes with optional and keyword arguments) and use it frequently. My rule is however that if I ever want to introduce bindings of any kind I will use defmacro. Simple. Saves me a lot of pain. But when it comes to macros there is no truth. This discussion has been going on long enough for most o us to know that it is a matter of taste.

Call/cc is overkill. It is a shitty, leaky abstraction that nobody really wants. Delimited continuations are the bee's knees! They compose, capture just the things you tell it to and are fast. They follow the idea of having a well chosen set of primitives as building blocks. You want CL's tagbody? No problem. Fast coroutine style generators? You got it. Cooperative, fiber based multitasking? Just a pure scheme library waiting to be used!


While I believe general continuations are too powerful to be really useful in real-world production programs, delimited continuations really ought to be possible. See http://okmij.org/ftp/continuations/#tutorial for example. They are quite similar to the Cont monad in Haskell, and are occasionally quite useful.


> JavaScript isn't Scheme, but it's close enough for most programmers working in the real world.

Yeah, a Buick is like a Toyota. Both can get you where you want to go. But close enough?


I learned lisp for probably a good 60 minutes (!) and it’s an eye opener for JS. A lot more JS idioms make sense now. Well worth doing if your a JS slinger.


I had a very nice experience when trying rust with a couple of friends. I just wrote rust much like I would write scheme and, after using immutable.rs, I wrote pretty efficient code without actually fighting the borrow checker at all.

My friends, coming from hopelessly mutable languages like python, could hardly get any work done at all.

This was back in late 2017, and things might have gotten better since.


I did it the other way around. I wrote some JS before I really learned about JS idioms and a lot of my earlier code looked weird. Like the way I construct an object is to write a function (constructor) that does initialization and then returns an object full of closures, instead of assigning a function to Foo.prototype.bar etc.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: