[racket] Quoted expressions in #lang racket

443 views
Skip to first unread message

Racket Noob

unread,
Sep 18, 2011, 10:15:58 AM9/18/11
to us...@racket-lang.org
In Common Lisp or Clojure REPL, expression '(1 2 3) evaluates to (1 2 3).
But in #lang racket the same expression evaluates to '(1 2 3). Why?

Grant Rettke

unread,
Sep 18, 2011, 10:34:12 AM9/18/11
to Racket Noob, us...@racket-lang.org
2011/9/18 Racket Noob <racke...@hotmail.com>:

> In Common Lisp or Clojure REPL, expression '(1 2 3) evaluates to (1 2 3).
> But in #lang racket the same expression evaluates to '(1 2 3). Why?

In the bottom left hand of the screen in DrRacket click the "Choose
Language" dropdown, "Use the language declared in source" should be
selected on the left.

On the right you can choose the "Output Syntax". If you change it to
"write" then it will look how you want.
_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users

Matthew Flatt

unread,
Sep 18, 2011, 10:38:38 AM9/18/11
to Racket Noob, us...@racket-lang.org

In Racket, as in Common Lisp and Clojure, the expression

'(1 2 3)

produces a list of three numbers. The only difference in this case
among the languages is how they print. Racket's default printing mode
prints values in the REPL in the same way as expressions, so it prints
the list of three numbers as

'(1 2 3)

Matthias Felleisen

unread,
Sep 18, 2011, 10:44:16 AM9/18/11
to Grant Rettke, us...@racket-lang.org

On Sep 18, 2011, at 10:34 AM, Grant Rettke wrote:

> 2011/9/18 Racket Noob <racke...@hotmail.com>:
>> In Common Lisp or Clojure REPL, expression '(1 2 3) evaluates to (1 2 3).


No it doesn't. In CL and Clojure, '(1 2 3) evaluates to '(1 2 3) and then the printer turns it into (1 2 3).

Now imagine you wish to experiment at the REPL. (What an outrageous idea but some of us do.) In that case, you may wish to reuse a result from some REPL computation in the repl again. Just paste it back in and run. Ouch for Common Lisp. Ouch for Clojure:

function expected; given 1

This issue was clarified in a beautiful MIT dissertation around 1980 (Brian Smith) and nailed once and for all. Sadly Brian chose a horrible slogan, which the rest of the MIT lispers didn't understand and so his ideas got buried. I re-discovered them and so did many others.

Go figure why Lispers are hung up on a mistake from the 1950s.

-- Matthias

Racket Noob

unread,
Sep 18, 2011, 10:59:56 AM9/18/11
to us...@racket-lang.org
> >> In Common Lisp or Clojure REPL, expression '(1 2 3) evaluates to (1 2 3).
>
>
> No it doesn't. In CL and Clojure, '(1 2 3) evaluates to '(1 2 3) and then the printer turns it into (1 2 3).
>

Wait a minute, I dont get it! You are saying that (quote (1 2 3)) evaluates to (quote (1 2 3)) ?
Sorry, it doesn't make any sanse to me. :(
As I aunderstand things, quote is a special forms that instructs lisp not to evaluate the a form in applicative order, but rather treat it as a literal.
 

Shriram Krishnamurthi

unread,
Sep 18, 2011, 11:15:41 AM9/18/11
to Racket Noob, us...@racket-lang.org
Yep, that's what he's saying.

I know why you're confused. Let me see if I can help.

Here's an input program:

'(1 2 3)

Now be careful to make the following distinction:

- what it computes
- what it prints

What it computes is a list with three values. There are at least
three different ways to PRINT this:

1. (1 2 3)
2. #<list>
3. (quote (1 2 3))

The first has the disadvantage Matthias pointed out: you can't paste
the value back in in a bigger computation. The second has the same
disadvantage. The third has the advantage you can paste it back in.

You're probably concerned that pasting it back in "makes a new list".
Yes, it does. But if the expression '(1 2 3) were part of some bigger
computation -- eg,

(length '(1 2 3))

-- then no "new list" would be created. So it's only if you try
copying the output of one computation as the input of another that
there might be new allocation. But look at the word I just used:
"copy".

This isn't the full answer, but I think you need to make sure you've
got at least these steps under your belt before we go further. Do ask
questions.

Shriram

Racket Noob

unread,
Sep 18, 2011, 12:12:35 PM9/18/11
to s...@cs.brown.edu, us...@racket-lang.org
Saying that (quote (1 2 3)) evaluates to (quote (1 2 3)) [instead to (1 2 3)] is the same nonsanse to me like saying that (+ 1 2) evaluates to (+ 1 2) [instead to 3].

Shriram Krishnamurthi

unread,
Sep 18, 2011, 12:22:27 PM9/18/11
to Racket Noob, us...@racket-lang.org
I used different words than Matthias because we were trying to offer
somewhat different explanations of what is happening. You chose to
use his words in response to mine, which only confuses things further.

(There is, incidentally, a good reason why (+ 1 2) could, but does
not, evaluate to (+ 1 2).)

But overall, since I appear to be talking nonsense, I'll avoid
following-up and aggravating you further. Good luck.

John Clements

unread,
Sep 18, 2011, 12:25:26 PM9/18/11
to Racket Noob, us...@racket-lang.org, s...@cs.brown.edu

On Sep 18, 2011, at 9:12 AM, Racket Noob wrote:

> Saying that (quote (1 2 3)) evaluates to (quote (1 2 3)) [instead to (1 2 3)] is the same nonsanse to me like saying that (+ 1 2) evaluates to (+ 1 2) [instead to 3].

Be careful with words like "nonsense" :).

What does 3 evaluate to?

3

So, numbers evaluate to themselves. That's because numbers are "values".

In a similar way, #t evaluates to

#t

because it's also a value.

What about (list 1 2 3)? It's *also* a value. That is, (list 1 2 3) evaluates to a list containing three things, the numbers 1, 2, and 3. In Racket, this gets printed as

'(1 2 3)

... so that, like other values, its printed representation is also a legal program piece.

Does this choice make more sense now?

John

Eli Barzilay

unread,
Sep 18, 2011, 12:34:34 PM9/18/11
to Racket Noob, us...@racket-lang.org, s...@cs.brown.edu
20 minutes ago, Racket Noob wrote:
>
> Saying that (quote (1 2 3)) evaluates to (quote (1 2 3)) [instead to
> (1 2 3)] is the same nonsanse to me like saying that (+ 1 2)
> evaluates to (+ 1 2) [instead to 3].

Yet another view:

(+ 1 2) evaluates to 3 is nonsense, it really evaluates to three.

(+ 1 2) evaluates to 3 is nonsense, it really evaluates to "3".

(+ 1 2) evaluates to 3 is nonsense, it really evaluates to three.

(+ 1 2) evaluates to 3 is nonsense, it really evaluates to #b00000011.

(+ 1 2) evaluates to 3 is nonsense, it really evaluates to ^C.

...

All Schemes and Lisps evaluate (list 1 2 3) into the same list,
including Racket. It just gets *printed* in some form that is
intended for human consumption.

And BTW, the different printout is not a Racket invention -- it is
used in scheme48/scsh. Or in MIT Scheme the printout is something
like ";; value: (1 2 3)" and obviously the ";;" prefix is not part of
the value.

--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://barzilay.org/ Maze is Life!

Matthias Felleisen

unread,
Sep 18, 2011, 12:41:24 PM9/18/11
to Eli Barzilay, us...@racket-lang.org, s...@cs.brown.edu

Mr Noob: if (1 2 3) is a value, why can't I compute (car (1 2 3)). 4 is a value and I can compute (+ 4 3). #t is a value and I can compute (not #t). Why do you insist that I cannot compute with (1 2 3) if it is a value?

Racket Noob

unread,
Sep 18, 2011, 1:02:30 PM9/18/11
to s...@cs.brown.edu, us...@racket-lang.org

Sorry Shriram, i didn't mean to insult you or anyone else, but my poor english prevents me to express myself clearly. Still, i will try to explain what bothers me with the way Racket prints quoted expressions and I hope that you'll understand what i want to say:

Suppose that we enter expression (quote (1 2 3)) in REPL. Let's see what's happen next:
 
1) Lisp reader reads what we entered and converts it to his own internal representation of list. That list it passes to evaluator.
 
2) Evaluator analyse given list and recognize that it contains a symbol quote at its first position, which is signal to lisp that it shoud return its (only) parameter untouched. So, evaluator does just that: as result of evaluation, it returns a list (1 2 3).
 
Hence, I think it would be reasonable that REPL print back just that, (1 2 3), as in CL or Clojure, and not '(1 2 3) as in Racket, because quote is already "consumed" in step 2) when evaluator "eats" it while processed the quote special form. For me, it's just plain wrong to print '(1 2 3) because quote is already gone.

> From: s...@cs.brown.edu
> Date: Sun, 18 Sep 2011 12:22:27 -0400
> Subject: Re: [racket] Quoted expressions in #lang racket
> To: racke...@hotmail.com
> CC: us...@racket-lang.org
>

Grant Rettke

unread,
Sep 18, 2011, 1:05:20 PM9/18/11
to Matthias Felleisen, Eli Barzilay, s...@cs.brown.edu, us...@racket-lang.org
On Sun, Sep 18, 2011 at 11:41 AM, Matthias Felleisen
<matt...@ccs.neu.edu> wrote:
>
> Mr Noob: if (1 2 3) is a value, why can't I compute (car (1 2 3)). 4 is a value and I can compute (+ 4 3). #t is a value and I can compute (not #t). Why do you insist that I cannot compute with (1 2 3) if it is a value?

Maybe RacketNoob can start by doing this:

"In the bottom left hand of the screen in DrRacket click the "Choose
Language" dropdown, "Use the language declared in source" should be
selected on the left.

On the right you can choose the "Output Syntax". If you change it to
"write" then it will look how you want."

And then we can point him at some good things to read that will help
him make sense of all the good points and advice everyone has shared.

Perhaps: Racket reader documentation, quote documentation, Scheme
standard? That is how I learned. I loved this passage from the R6RS
spec:

``It is important to distinguish between the mathematical numbers, the
Scheme objects that attempt to model them, the machine representations
used to implement the numbers, and notations used to write numbers.''

Racket Noob

unread,
Sep 18, 2011, 1:20:29 PM9/18/11
to us...@racket-lang.org

 You can't compute (car (1 2 3)) because before car even begin, it's parameter, list (1 2 3) must be evaluated, but 1 is not a procedure name. It is different than in (quote (1 2 3)) where such evaluation doesn't take place.
 
> Date: Sun, 18 Sep 2011 12:05:20 -0500
> From: gre...@acm.org
> To: matt...@ccs.neu.edu
> CC: e...@barzilay.org; s...@cs.brown.edu; us...@racket-lang.org

> Subject: Re: [racket] Quoted expressions in #lang racket
>

Shriram Krishnamurthi

unread,
Sep 18, 2011, 1:33:47 PM9/18/11
to Racket Noob, us...@racket-lang.org
You keep thinking (1 2 3) is the canonical form of a list. It is
not. It's just a particular *print representation* of list. So is
#<list> or one of the many alternatives Eli proposed.

Your attempt to use an interpreter model is commendable but falls
short. That is because you only described the READ and EVAL steps of
a REPL. The L(oop) is not relevant here, but the P(rint) is actually
the most critical part, and that's the one you left out of your
attempt at explaining what's happening.

Also, Matthias asked you about substituting answers inside bigger
expressions. You gave him a mechanical answer of why (you think) it
won't work, but you failed to understand the bigger point he was
trying to make in the first place.

Racket Noob

unread,
Sep 18, 2011, 1:45:06 PM9/18/11
to s...@cs.brown.edu, us...@racket-lang.org
 
> You keep thinking (1 2 3) is the canonical form of a list. It is
> not. It's just a particular *print representation* of list. So is
> #<list> or one of the many alternatives Eli proposed.
>
 
Oh, I understand that. It's just that I don't understand why you (i.e. Racket implementers) choose Racket by default prints list this way (different than all other lisps). I think this choice can confuse beginners (and all other users who switches from different lisp implementations and expects "traditional" REPL behaviour). 

Matthias Felleisen

unread,
Sep 18, 2011, 1:49:42 PM9/18/11
to Racket Noob, us...@racket-lang.org, s...@cs.brown.edu

Just because Lisp got it wrong for 22+ years and most Lisps are still doing it wrong, we don't have to continue making the same mistake. Long live 2Lisp, 3Lisp, and all other rational Lisps.

Shriram Krishnamurthi

unread,
Sep 18, 2011, 1:57:30 PM9/18/11
to Racket Noob, us...@racket-lang.org
> It's just that I don't understand why you (i.e.
> Racket implementers) choose Racket by default prints list this
> way (different than all other lisps). I think this choice can confuse
> [...] users who switches from different lisp
> implementations [...]

Then it nicely accomplishes the task of alerting them that there are
many more surprises ahead.

(If Racket were just the same as some other Lisp, it would have no
need to exist.)

Richard Cleis

unread,
Sep 18, 2011, 2:26:43 PM9/18/11
to Racket Noob, us...@racket-lang.org, s...@cs.brown.edu

On Sep 18, 2011, at 7:45 AM, Racket Noob wrote:

>
> > You keep thinking (1 2 3) is the canonical form of a list. It is
> > not. It's just a particular *print representation* of list. So is
> > #<list> or one of the many alternatives Eli proposed.
> >
>
> Oh, I understand that. It's just that I don't understand why you (i.e. Racket implementers) choose Racket by default prints list this way (different than all other lisps). I think this choice can confuse beginners (and all other users who switches from different lisp implementations and expects "traditional" REPL behaviour).

They partly made the choice for people like me, who didn't experience their courses or work through the the early chapters in HtDP; our group is still suffering from software I wrote before I understood the difference between the R and P in REPL (using several earlier versions of Scheme). I believe the Racket REPL would have eliminated that confusion. I also find flights over the ocean are more comfortable with turbine engines than piston engines.

rac

>
> > Your attempt to use an interpreter model is commendable but falls
> > short. That is because you only described the READ and EVAL steps of
> > a REPL. The L(oop) is not relevant here, but the P(rint) is actually
> > the most critical part, and that's the one you left out of your
> > attempt at explaining what's happening.
> >
> > Also, Matthias asked you about substituting answers inside bigger
> > expressions. You gave him a mechanical answer of why (you think) it
> > won't work, but you failed to understand the bigger point he was
> > trying to make in the first place.
> >
> > Shriram

Marco Morazan

unread,
Sep 18, 2011, 3:16:14 PM9/18/11
to Racket Noob, us...@racket-lang.org
2011/9/18 Racket Noob <racke...@hotmail.com>:

>
>  You can't compute (car (1 2 3)) because before car even begin, it's
> parameter, list (1 2 3) must be evaluated, but 1 is not a procedure name. It
> is different than in (quote (1 2 3)) where such evaluation doesn't take
> place.
>

Yes, so does that not alert you that (1 2 3) is the "nonsense" part?
There is no value that is (1 2 3).

I kindly suggest the thought that omitting the quote is precisely what
makes things harder for beginners. It seems to suggest to the
untrained that REPL is returning something that is not a value. As
Matthias and others have pointed out, you can not take the "value" (1
2 3) and use it somewhere else. What sense does that make?

I also believe John brought the point home for you. If 3 "evaluates"
to 3, then why should '(1 2 3) not "evaluate" to '(1 2 3)? They are
both constants and should exhibit similar behavior when evaluated.

--

Cheers,

Marco

Racket Noob

unread,
Sep 18, 2011, 4:04:59 PM9/18/11
to mora...@gmail.com, us...@racket-lang.org
 
> I kindly suggest the thought that omitting the quote is precisely what
> makes things harder for beginners. It seems to suggest to the
> untrained that REPL is returning something that is not a value. As
> Matthias and others have pointed out, you can not take the "value" (1
> 2 3) and use it somewhere else. What sense does that make?
>
 
 
 
I think beginner should understand that list is basic lisp notion which serves (at least) two purposes:
 
1) list as data: as in (1 2 3) or as in whole lisp program
 
or
 
2) list as expression denoting function application: as in (+ 1 2)
 
Once when above two points is understood, there is no confusion at all. I think that masking those facts when teaching doesn't contribute to beginner's greater understanding of the true nature of lisp.
 
 

Shriram Krishnamurthi

unread,
Sep 18, 2011, 4:20:30 PM9/18/11
to Racket Noob, us...@racket-lang.org, mora...@gmail.com
We are not teaching Lisp. We're teaching Racket.

Robby Findler

unread,
Sep 18, 2011, 4:29:36 PM9/18/11
to Racket Noob, us...@racket-lang.org, mora...@gmail.com
2011/9/18 Racket Noob <racke...@hotmail.com>:

> I think beginner should understand that list is basic lisp notion which
> serves (at least) two purposes:
>
> 1) list as data: as in (1 2 3) or as in whole lisp program
>
> or
>
> 2) list as expression denoting function application: as in (+ 1 2)

FWIW, as one PL educator, I don't find that to be something I wish to
teach to the students who are beginning to learn what is important
about programming languages. I also don't think that a list is a
particularly good representation for a function application in an
implementation and as a mental device I think it can only confuse to
have two distinct concepts mapping in a single concrete thing.

Robby

Racket Noob

unread,
Sep 18, 2011, 4:41:08 PM9/18/11
to ro...@eecs.northwestern.edu, us...@racket-lang.org
> FWIW, as one PL educator, I don't find that to be something I wish to
> teach to the students who are beginning to learn what is important
> about programming languages. I also don't think that a list is a
> particularly good representation for a function application in an
> implementation and as a mental device I think it can only confuse to
> have two distinct concepts mapping in a single concrete thing.
>
> Robby
 
 
 
Ok, maybe this is not something that's important in other programming languages, but it *is* important in lisps. As a lisp educator, how can you *not* to teach this fundamental fact about lisp?

Robby Findler

unread,
Sep 18, 2011, 4:44:03 PM9/18/11
to Racket Noob, us...@racket-lang.org
2011/9/18 Racket Noob <racke...@hotmail.com>:

I don't really see how to give a different answer to this question
than the one before.

I guess I consider myself a more general purpose educator and, IMO,
this (flawed) design decision is not worth explaining.

Don't get me wrong, there is a LOT to love about Lisp and I am
grateful for that heritage and how it shows up in Racket. I just don't
consider this particular detail to be the One True Way.

Shriram Krishnamurthi

unread,
Sep 18, 2011, 4:47:45 PM9/18/11
to Racket Noob, us...@racket-lang.org, ro...@eecs.northwestern.edu
> Ok, maybe this is not something that's important in other programming
> languages, but it *is* important in lisps. As a lisp educator, how can you
> *not* to teach this fundamental fact about lisp?

It's funny that here you're berating Robby, who's put more time into
different ways of printing than anyone I can think of in the Lisp
community. Take a look at the options offered in the "Show Details"
part of language selection. In particular, the quasiquote
representation is probably a better way to help students understand
the issues you think are vital.

Shriram

Racket Noob

unread,
Sep 18, 2011, 5:01:36 PM9/18/11
to us...@racket-lang.org
Such a cold community. :(
I give up. I'm sorry for bothering you with my bad english and stupidity, I'll never post to this group again. 
 
> From: s...@cs.brown.edu
> Date: Sun, 18 Sep 2011 16:47:45 -0400
> Subject: Re: [racket] Quoted expressions in #lang racket

Neil Van Dyke

unread,
Sep 18, 2011, 5:09:29 PM9/18/11
to Racket Noob, us...@racket-lang.org, ro...@eecs.northwestern.edu
Racket Noob wrote at 09/18/2011 04:41 PM:
> Ok, maybe this is not something that's important in other programming
> languages, but it *is* important in lisps. As a lisp educator, how can
> you *not* to teach this fundamental fact about lisp?

To me, speaking of real use of the language, it seems a lot less
important in Racket than it used to be, in Racket's Lisp ancestors. I
suspect it can be saved for an aside, when introducing syntax
transformers ("and here, we can get the form as a list if we want") or
maybe "eval" ("this will rock your world: data can be code. you should
probably never do this").

Unless someone finds it useful in explaining how evaluation works. I
don't have significant experience teaching intro programming, so I tend
to defer to PLT professors on what they've found worked for their intro
students.

--
http://www.neilvandyke.org/

Robby Findler

unread,
Sep 18, 2011, 5:11:37 PM9/18/11
to Racket Noob, us...@racket-lang.org
FWIW, I don't think anyone was bothered (only that we have a technical
disagreement) and I'm sorry to see you go.

Best wishes,
Robby

2011/9/18 Racket Noob <racke...@hotmail.com>:

John Clements

unread,
Sep 18, 2011, 5:31:21 PM9/18/11
to Racket Noob, Racket Users

On Sep 18, 2011, at 2:01 PM, Racket Noob wrote:

> Such a cold community. :(

Cold? No way! We're *hot*. That is: we're eager to discuss, and eager to argue.

If anything, we're holding back, to avoid making you angry. Maybe we should have held back a bit more? I know it can feel a bit lonely when everyone disagrees with you.

A truly obstinate learner will continue arguing until he figures out what's going on in everyone else's brain, and why they think the way they do. This group is full of passionate people who care a *lot* about teaching!


John

Danny Yoo

unread,
Sep 18, 2011, 5:38:25 PM9/18/11
to Racket Noob, us...@racket-lang.org
> Such a cold community. :(
> I give up. I'm sorry for bothering you with my bad english and stupidity,
> I'll never post to this group again.

Hello!

Whoa! I think you are reading a lot more aggression out of those
replies than what actually exists. Your english is fine; no one has
made a single remark about it. (Um, unless the previous sentence
counts...)


If it helps: the replies to this thread cover at least two or three
separate things.

1. They've shown you how to set up DrRacket so it prints things
the traditional Lisp way. If you adjust it in the language preference
menu, values should print exactly as they would in a traditional Lisp.

Have you been able to get this to work, or is the language preference
menu not working for you? Changing the default should be about two or
three mouse clicks, if I remember right.


2. Several people have given a justification for why the default
in Racket prints things in a way that's different from what you're
used to. The difference is not accidental: it's there by design. For
example, you can see Section 3.3 of
http://www.cs.brown.edu/~sk/Publications/Papers/Published/fffkf-drscheme-journal/paper.pdf,
as well as Section 2.1 of Wadler's "Why Calculating is Better than
Scheming" (http://www.cs.kent.ac.uk/people/staff/dat/miranda/wadler87.pdf)

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.
Admittedly, this means that Racket's default printing behavior is
deviating from traditional Lisps. But changing the default to Lisp
style should be easy to do. Is that sufficient for you, or do you
have a proposal?

3. There's a little bit of silliness on the thread because of the
situation: it's not clear from the email thread that you realize that
you're talking directly with several of the authors of DrRacket. You
have got incredible access to them on this mailing list.

Best of wishes to you!

Danny Yoo

unread,
Sep 18, 2011, 5:53:40 PM9/18/11
to Racket Noob, Racket mailing list
[CCing the Racket mailing list]


> 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?

Oh! Then it should just print like Lisp mode, if I remember
correctly. Give me a sec; let me double check that.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$ racket
Welcome to Racket v5.1.2.
> (list 1 2 3)
'(1 2 3)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Oh! So I'm wrong about that. No problem. Let me just change a
parameter here...

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (print-as-expression #f)
> (list 1 2 3)
(1 2 3)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Ok, now it should behave as you expect. I'm using the
print-as-expression parameter here to control the default printer.
For reference:

http://docs.racket-lang.org/reference/Writing.html#(def._((quote._~23~25kernel)._print-as-expression))


If you want to make that the default on your end, I think you can add
a line to your $HOME/.racketrc, so that this parameter is up
automatically when Racket's being run as a repl.

Stephen Bloch

unread,
Sep 18, 2011, 5:58:49 PM9/18/11
to Racket Noob, Racket mailing list

On Sep 18, 2011, at 4:41 PM, Racket Noob wrote:

Ok, maybe this is not something that's important in other programming languages, but it *is* important in lisps. As a lisp educator, how can you *not* to teach this fundamental fact about lisp?

Two questions:
1) How many people here are Lisp educators?  Most of us seldom if ever use Lisp, but use Racket every day.
2) Is "representing expressions as lists" really a fundamental fact about Lisp, or is it an implementation decision taken by some of the early implementers of Lisp?

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.

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.  So when you type the eight characters "'(1 2 3)", what happens?
1) The reader converts this into a syntax object containing "quote" and a nested syntax object containing "1", "2", and "3".
2) The evaluator converts this into an internal representation of a list containing 1, 2, and 3
3) The printer converts this into the eight characters "'(1 2 3)"

I don't understand why you (i.e. Racket implementers) choose Racket by default prints list this way.

In part because of our experience in the classroom.  For beginners, it's convenient for the read-eval-print sequence to be idempotent, i.e. if you do it twice, you get the same result as if you had done it once.  In other words, anything you get as an answer to a question can be copied and pasted back in, and you'll get it again.  And you're right, that was NOT true of classic Lisp.  Suppose the variable y has the value (list '+ 3 4); then if I type the two characters "'y" into a REPL, I get the one character "y"; if I type the one character "y" into the REPL, I get the seven characters "(+ 3 4)"; and if I type this into the REPL, I get the one character "7".

In our experience, this confuses students, so we use an analogy more like arithmetic or algebra.  Don't think of the operation as "evaluating" but rather "simplifying as far as possible."  In grade-school arithmetic, suppose x has the value 5, and I want to simplify "3 + 4x".  It simplifies to 3 + 4*5, which simplifies to 3 + 20, which simplifies to 23, which doesn't simplify any farther.  We've seen four different expressions along the way, but they all simplify to 23.

Now let's do that in Racket.  Suppose variable x has the value 5, and I type
(+ 3 (* 4 x))
This is simplified to (+ 3 (* 4 5)), which is then simplified to (+ 3 20), which is then simplified to 23, which can't be simplified any farther.  I can type any of these four expressions into a REPL, and I get the exact same result.

Now let's try this with lists, the way DrRacket does it by default.  I type in
(cons 1 (list 2 3 x))
which is simplified to (cons 1 (list 2 3 5)), which is then simplified to (list 1 2 3 5) (or, if you prefer, (cons 1 (cons 2 (cons 3 (cons 5 empty)))), which can't be simplified any farther.  I can type any of these four expressions into a REPL, and I get the exact same result.

Now let's try it the way you're thinking about it.  I type in
(cons 1 (list 2 3 x))
which is read as (list 'cons 1 (list 'list 2 3 'x)), which after one step of reduction produces (list 'cons 1 (list 'list 2 3 5)), which after another step of reduction produces (list 'cons 1 (list 2 3 5)), which after another step of reduction produces (list 1 2 3 5), which you want to print out as (1 2 3 5).  We've seen six different expressions.  Typing these six different expressions into a REPL gives you five different answers, one of which is an error message.

Does that help?


Stephen Bloch

Ivanyi Peter

unread,
Sep 18, 2011, 7:32:21 PM9/18/11
to us...@racket-lang.org
Hi All,
 
Just my two cents. :-) I am coming from the "original Lisp" point of view as well.
At the beginning of the discussion I have not undertood any of the answers. They were
"very cryptic" to me as well, but I have to say that these two papers made clear what
is the position of DrRacket and I understand this. I am not sure why these papers made it
clear and the discussion did not. Sorry.
I will even try to incorporate these into my own teaching and thinking. :-)
I am still with DrRacket. :-)))
 
Peter Ivanyi

Danny Yoo <dy...@cs.wpi.edu> írta:

Eli Barzilay

unread,
Sep 18, 2011, 8:09:23 PM9/18/11
to Stephen Bloch, Danny Yoo, us...@racket-lang.org
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!

Reply all
Reply to author
Forward
0 new messages