# Does anyone know what version of Scheme this is?

The one I'm talking about is the one on replit.com. Pic:

Oh and the first two examples for it are a Y-combinator and a macro.

the biwascheme interpreter version 0.6.4. it's a scheme interpreter written in javascript. its website is biwascheme.org.

Ok, but is it R5RS, R6RS, or what?

Because:

i dunno just look at the website
it says this at least

Yeah... I don't want to use R6RS or R7RS.

/*
* BiwaScheme 0.6.4 - R6RS Scheme in JavaScript
*
* Copyright (c) 2007-2014 Yutaka HARA (http://www.biwascheme.org/)
*/


R6RS...

You could check out UCB Scheme.

Wait what’s wrong with R6RS

I don't see a "use online" option there.

Brian could probably tell you.

There are two dialects of Lisp in common use today: Scheme and Common Lisp. Guy Steele, who was a co-developer of both of them, compares Scheme to his Swiss Army knife, which has a limited set of tools (five linear-head screwdrivers, one Philips-head, for example) but can come with him everywhere; he compares Common Lisp to his home workshop, which has a whole wall full of dozens of screwdrivers, including special-purpose ones such as non-metallic as well as different sizes of different head patterns.

But Scheme has gotten bigger and more industrial-strength with each revision of the standard. A big shift between R4 and R5 was the specification of hygienic macros, a change that I bitterly opposed at the time, partly because of a slew of messages on comp.lang.scheme from Lords of the Lambda Calculus (a name I just made up, like Knights of the Lambda Calculus but superstars) saying "I can't figure out how to do such-and-such with hygienic macros," but have since grudgingly come to accept for lexically scoped languages (i.e., not Logo).

But R6 was a huge shift away from Scheme's educational roots toward "real world" industrial programming. For example, R6 removes the requirement that the language have a Read-Eval-Print Loop (REPL), i.e., the requirement that it be usable interactively. You can have a Scheme built into some piece of software but invisible to the user of that software. A seemingly minor change that drives me crazy is that they made symbols case-sensitive, which is so wrong even though all the common programming languages do it. Upper case is a font decoration, like italics. There are conventions about when these decorations are used, e.g., capitalizing the first word of a sentence, or italicizing imports from foreign languages, such as ipso facto or ibid from Latin. But those are just typographic conventions; it would be weird if there were a different English word "ibid" that meant something different. You can find counterexamples to what I'm saying, especially back in the 1800s when people were giving their children names like Faith and Charity. You can imagine crafting sentences such as "Yesterday Charity didn't show much charity" in which the two otherwise identically spelled words are semantically distinguished by the initial capital letter, but those are super exceptional. (And I point out that if someone said that to you out loud instead of in writing, you'd have no trouble figuring out which "charity" was which without the aid of the capital C.) And there are plenty of weird homophones in English that don't involve capitalization.

Case-insensitivity matters so that you can easily write sentences about programs, such as "You should really use MAP in there somewhere," or annotated programs, such as "You left out the MAP in (sum (MAP (square()) OVER (x)))" when someone asks why (sum (square (x)) didn't work.

And lots more; they invented a module system -- which is only needed in industrial-strength programming with teams of 500 programmers -- and a bunch more that I forget.

This all happened because the standardization committee was invaded by people who wanted Scheme to be another Common Lisp, basically, although they didn't say it that way. Instead they said things like "All modern programming languages do such-and-such" but that comes down to the same thing, because the languages they call "modern" were invented for teams of 500, not for teaching the central ideas of computer science. And also because Steele and Sussman, the developers of Scheme, were spending their time on other things and didn't attend the R6 meetings. If they had, the world would be a better place. (They are, in public, neutral about the changes to Scheme, I should point out.)

The big point is, we already had a Lisp for teams of 500, namely, Common Lisp. So the invaders should have just learned to love CL instead of mucking up Scheme.

The above does not represent the opinion of the University of California, blah blah.

Yeah that's true. Are you on a Chromebook or something? I think maybe you can find an R5RS library for Racket a/k/a Dr. Scheme.

Nope. Windows 10.

Oh. Well then why does it matter if it's a web server or runs locally?

I wonder if

(define-macro for
(lambda (iterator start end . body)
(let loop ((,iterator ,start))
(if (<= ,iterator ,end)
(loop (+ ,iterator 1) (begin ,@body))))))

(for x 1 3
(for y 1 3
(for z 1 3
(define a (* x y z))
(print x " * " y " * " z " = " a))))


is valid R5RS code. It outputs the expected output:

1 * 1 * 1 = 1
1 * 1 * 2 = 2
1 * 1 * 3 = 3
1 * 2 * 1 = 2
1 * 2 * 2 = 4
1 * 2 * 3 = 6
1 * 3 * 1 = 3
1 * 3 * 2 = 6
1 * 3 * 3 = 9
2 * 1 * 1 = 2
2 * 1 * 2 = 4
2 * 1 * 3 = 6
2 * 2 * 1 = 4
2 * 2 * 2 = 8
2 * 2 * 3 = 12
2 * 3 * 1 = 6
2 * 3 * 2 = 12
2 * 3 * 3 = 18
3 * 1 * 1 = 3
3 * 1 * 2 = 6
3 * 1 * 3 = 9
3 * 2 * 1 = 6
3 * 2 * 2 = 12
3 * 2 * 3 = 18
3 * 3 * 1 = 9
3 * 3 * 2 = 18
3 * 3 * 3 = 27


R5 specifies the hygienic macro language but punts on non-hygienic macros. (It turns out that once in a while you need them.) There were too many competing notations, and at the time, at least, no principled reason to pick one over another.
So if your code works, it's legal.

Ok.

I don't actually know the difference between those.

Ah. You are pulling at the end of a long thread.

Once upon a time, Lisp interpreters were dynamically scoped. That is, if you use a variable in a procedure body, and that variable isn't defined in that same procedure, you look next in the caller of the procedure, and then the caller of that procedure, until finally you get to a toplevel call and you check the global variables.

It turns out that dynamic scope is the easy, obvious thing to implement in an interpreter, but lexical scope (which I'll get to in a moment) is the easy thing to implement in a compiler, and for quite a long time, Lisp systems included both an interpreter (for development and debugging) and a compiler (for fast production runs), and the interpreter used dynamic scope, while the compiler used lexical scope. The fact that this worked at all is a testament to the rareness of a procedure needing to use a local variable defined in an "uplevel" procedure.

So, one of the reasons people have rejected dynamic scope is its "name capture" problem. (Look up "funarg problem" for the classic papers working this out.) Say you do this:

(define pi 3.141592654)
(define (area r)
(* pi r r))


Straightforward, right? Now try this:

(define (big-area r)
(let ((pi 7))
(area r)))


With dynamic scope, the procedure BIG-AREA has captured the value of PI, which AREA needs to be correct.

So the new idea, lexical scope, is that if a procedure uses a variable that it didn't define itself, it looks in the physically surrounding procedure definition. For example, with lexical scope, AREA always uses the global PI, regardless of what BIG-AREA does, because the definition of AREA is at toplevel, not inside another procedure body. But the internal procedure generated by the LET in BIG-AREA (remember, the LET is equivalent to

( (lambda (pi) (area r)) 7)


) is created inside another procedure, namely BIG-AREA, so it has access to that procedure's R.

So, no name capture problem. The idea is that when you're debugging, all procedure definitions that might affect the procedure you're debugging are right there, surrounding that procedure, so you can't miss lexical name captures (which aren't called that, because they're always intentional), unlike the situation with dynamic scope, in which the definitions of AREA and BIG-AREA could be miles apart in the program source.

So, as I said, no name capture problem. Unless you're using macros. So you say

(define-macro (big-area r)
(let ((pi 7))
(* ,pi r r)))


and the macro has snuck a quasi-dynamic reference to its own PI into the calculation. (I know, this isn't a great example, I'm too tired to look one up.)

So, finally, hygienic macros maintain the principle of dynamic scope by rigidly separating symbols that will be evaluated in the macro's own environment from symbols that will be evaluated in the caller's environment. The latter can't overwrite the caller's expectations because, in one standard implementation, all the caller's-environment variables are renamed for each macro call, so the name PI might turn into PI#1 on the first call, PI#2 on the second call, etc. (I'm just making up a notation that wouldn't be a legal symbol, so you can't type in these renamed variables to get a value from a different scope.)

Now you understand what problem hygienic macros are supposed to solve, and you can look up the details of the actual notation.