[plt-scheme] Re: Paren Paralysis Sufferers Unite

From: Gregory Marton (gremio at acm.org)
Date: Fri Oct 16 19:27:36 EDT 2009

Hi Morgan,

There is a purpose to the madness.  Others have told you that the "extra" 
parentheses are read by Scheme as another procedure application -- it "expected 
a procedure" as the first item in ()s.  What it found was a boolean value 
instead.  Okay.  Why would it expect a procedure?  What's the point of 
expecting a procedure instead of just passing on whatever value is there, like 
math does?  When is that kind of thing useful?

When do we pass procedures around elsewhere?  You might get just the even 
numbers out of a list like this:
     (define some-numbers '(3 2 4 1 5 7 2))
     (filter even? some-numbers)
Here we are passing a procedure to filter, and it calls that procedure.
Okay, so it's nice to be able to pass procedures around.

Bear with me while I make up some non-existent functions for the purpose of 
illustration.  This may be more than you wanted to know, but it's an attempt to 
get at the heart of the matter.

What if you had a function it-is-bright that told you what time of day it is. 
Now you can write
     (define (notify-for-phone-call)
        (if (it-is-bright)
Wouldn't that be cool in the movie theater?

Now what you want now is to make the backlight brighter whenever it's dark. But 
your function is it-is-bright so you seek out your friendly
     (define (complement fn)
       (lambda () (not (fn))))
This new function complement takes any function (of zero arguments) and turns 
it into a new function (also of zero arguments) that returns the boolean 
opposite of whatever the original function would have returned. It's pretty 
easy to make this work with any number of arguments rather than exactly zero, 
but it's also unimportant.  Armed with complement, you can now write
     (define (ensure-backlight)
       (when ((complement it-is-bright))
             (set-backlight! 1)))

Now look, I've used an "extra" set of parentheses.  What did it do for me?
I called complement, giving it a function it-is-bright.  Complement returned a 
new function that would say the opposite of whatever you gave it.  But that's a 
function, so I need to invoke it.  If I don't invoke it, then the "when" form 
is testing the function itself, rather than its result.  What would happen? 
Let's try:
      (if even? "the even? function is considered true" "nope")
Go ahead, try it.  Note that this is different from
      (if (even? 3) "three is even" "nope")
So the backlight would always get turned on.  The "extra" parentheses ran the 
new function, which ran the old function, and then did the right thing.
The function by itself is just considered a true value.

Now consider: what would happen if (5) meant the same as 5?  Now we have to 
distinguish somehow between the values we wanted to pass on, untouched, and the 
values that we should go ahead and evaluate.

In our brave new language, would this test ever fail?
       (when ((complement it-is-bright))
             (set-backlight! 1))

Do we pass on the complemented function as just a value, or do we evaluate it? 
How do we know which to do?  The complemented function is a perfectly good 
value, as far as Scheme is concerned.  You might be wondering whether 
complement returned any value at all, or whether it returned #f.

This example is contrived, of course, but this is why the parentheses are not 
"extra".  They mean "evaluate what's in here as a function and its arguments". 
They always mean that, and there's no ambiguity.  The error message reflects 
that it tried to do that and failed, because it didn't know how to use #t (the 
boolean true value that was the result of your and clause) as a function.

Hope that helps,

> taking an example; the difference between these two pieces of code.
> (define (get-smallest x y z)
>          (cond ((and (< x y) (< x z)) x)
>                ((and (< y x) (< y z)) y)
>                ((and (< z x) (< z y)) z)
>            )
> )
> scheme is all happy with that, but not with what's below:
> (define (get-smallest x y z)
>          (cond (((and (< x y) (< x z))) x)
>                (((and (< y x) (< y z))) y)
>                (((and (< z x) (< z y))) z)
>            )
> )
> which results in this lot:
> (get-smallest 1 2 3)
> . . procedure application: expected procedure, given: #t (no
> arguments)
> Now, I freely admit there's absolutely no utility in having those
> extra parens. But they do no harm! [I think. Being a newb could
> possibly mean being wrong about these things. However the sky hasn't
> fallen in yet, so I'm fairly hopeful]
> taking the typical math example ((2 + 2) * 3) I mean, we know those
> parens are useless, but they potentially help to clarify the situation
> if you're uncertain of the order of evaluation with arithmetric
> operators.

------ __@   Gregory A. Marton                 http://csail.mit.edu/~gremio
--- _`\<,_                                                     617-775-3005
-- (*)/ (*)         Purpose of life: be happy; help others be happy.

Posted on the users mailing list.