I started this as some quick comments, but it wrote itself into a long-winded explanation of why what Racket does is following the Lisp tradition *more* closely than other Lisps. Feel free to skip if you're not into meta-meta-syntax discussions...
Two hours ago, Danny Yoo wrote: > > So there's been a lot of thought about this, and the default in > Racket skews toward making it easier for students to think about > calculating. I disagree with the "for students" part. It's specifically trying to make it easier to use values printed on the *repl*, which is not where (htdp-style) newbies should spend much time. So IMO it's something that is useful in any context. An hour and a half ago, Danny Yoo wrote: > > Yes, I got this to work. But, what if I don't want to use > > DrRacket, but just pure old console Racket.exe instead? Or emacs? > > [...] > > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; > > (print-as-expression #f) > > (list 1 2 3) > (1 2 3) Even easier -- just use (current-print write), and you get the "traditional" behavior. Here's a quick demo: -> (current-print) #<procedure:pretty-printer> -> '(current-print write) '(current-print write) -> (current-print write) #<void> -> '(current-print write) (current-print write) Note that it also demonstrates how confusing things can be. IME, explanations on what Lisp's "'" is doing are extremely frequent. An hour and a half ago, Stephen Bloch wrote: > > Actually, in many ways I sympathize: when I first encountered Racket > (which was then called PLT Scheme), I took a similar > interpreter-based approach to understanding what it was doing > (having previously encountered Lisp and learned the same > "expressions are lists" dictum you learned). It turns out not as > helpful as one would think. The general principle is fine: for a language that allows meta-facilities like macros and `eval', you obviously need access to the structures that the implementation uses to represent code. This *has* always been one of Lisp's core ideas. But the *implementation* of this idea -- using *just* plain S-expressions for representing code falls short in many ways. For example, you cannot represent source location which is extremely important when you have a syntax error in some big source file. Now, in the Lisp world (mostly in CL), there is a tendency to stick with the code == sexprs equivalence no matter what. As a result, there are various hacks around these problems. The main one is to use a hash table that can fake adding the extra information to the sexprs, by mapping them into the extra information. That doesn't work with symbols: they're interned, so you cannot distinguish two occurences of the same symbol, and in some of these systems you can observe that limitation of the system (for example, they won't have source information for these cases). Also, writing well-behaved macros can be a PITA, because such macros need to be aware of this implicit extra information and make sure that they produce sexprs with the correct information artifically attached in the same way. To make things worse, in Scheme you have the issue of hygiene, which -- again -- means that you need more than plain s-expressions to represent code. Here too, there are solutions like the above, and solutions where some kinds of expressions (mostly symbols) are put in a "wrapper" that holds the extra syntactic context information. (You can see this in Scheme implementations where syntax is "mostly sexprs", except for identifiers that are no longer plain symbols.) > In fact, the Racket reader does NOT represent expressions as lists; > it represents them as "syntax objects", which (as I understand it) > can be nested in the same way lists can, but carry some additional > information. Right -- Racket's solution is to dump the illusion of direct correlation between syntax (= syntax objects) and data (s-expressions) and instead use a new type for syntax (which, unsurprisingly, is similar enough to s-expressions that it is trivial to convert syntax to sexprs). But that's not dumping the "spirit of Lisp" -- if anything, it's *following* that spirit to the letter. The *core* idea above is the one of "reifying" the compiler's representation in a way that is accessible to user code -- and that was the great thing about sexprs. As it turned out throughout the decades, plain sexprs cannot provide sufficient information -- so instead of following what everyone else does and cheating the additional information in, Racket chooses to expose the *true* syntax objects to user code. Hopefully this explains why I view this as being a more lispish solution than the one taken by, for example, common lisp. An additional benefit of that is that it is easier now to accomodate new languages. You are no longer bound by the limits of plain sexprs; your syntax representation is something that is more conveniently treated as what it was supposed to be: the intermediate "Abstract Syntax Tree" representation of code. In other words, it is a direct result of sticking to the "Code is Data", and even preferring that over "Code is Sexprs". Yet another coincidental advantage that is more student-oriented, is the fact that there is a better separation between representation of code and representation of other data. You're much less likely to confuse one for the other. It's mostly legacy that still makes the Racket `eval' accept sexprs. It would be cleaner to make something like (eval '(+ 1 2)) return '(+ 1 2) like any other quoted data, and instead require (eval #'(+ 1 2)) -- or (eval (syntax (+ 1 2))) if you want to evaluate the (+ 1 2) expression. Even better would be to make eval throw an error when it accept anything that is not a syntax object to begin with. That would make the difference between 123 and #'123 more meaningful, instead of the other Lisp-inspired hack of equating the 123 syntax with the 123 value. (And that's BTW, one of the very nice properties of 3-Lisp, which Matthias mentioned earlier.) -- ((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay: http://barzilay.org/ Maze is Life! _________________________________________________ For list-related administrative tasks: http://lists.racket-lang.org/listinfo/users