From: Erann Gat
Subject: Evaluating syntax
Date: 
Message-ID: <gat-0603001418570001@milo.jpl.nasa.gov>
In a recent posting I proposed a macro called BIND that allows you to
write code that looks like:

(bind x = 1 and y = 2 in
  (foo x y))

instead of

(let ( (x 1) (y 2) )
  (foo x y))

Some people objected to this macro on the grounds that it violated the
spirit of S-expressions.  For example, Tom Breton wrote:

> I don't think you have the feel for sexps.  Sticking parens around
> something may technically make it a sexp, but it doesn't make it a
> tolerable one.  A sexp should not have internal dependencies.  IMO
> even boa parameter lists are iffy.

All this led me to think about what is the true spirit of S-expressions.
John McCarthy himself once wrote that there were too many parentheses
in the COND macro, and that's about as strong an authority as it gets
in this game.  So the following would be OK according to McCarthy:

(cond condition action condition action ...)

instead of

(cond (condition action) (condition action) ...)

In the case of COND the extra parens actually do serve a purpose,
albeit a minor one: they save you the trouble of having to put in an
explicit PROGN in order to have multi-statement actions.  But the
extra parens in a LET don't even serve that purpose.  Why not have:

(bind (var val var val ...) ...)

instead of

(let ( (var val) (var val) ...) ...)

Surely this change would be in the same spirit as the COND change, and
so we can safely assume that McCarthy would not disapprove.

But I have little respect for arguments from authority.  Are there
higher principles to which we can appeal to resolve these issues?  Some
possibilities include:

1.  Readability (how hard is it for a human to read)
2.  Parsability (how hard is it for a machine to read)
3.  Robustness to errors (how likely is it that a small lexical error
will result in a large semantic error)
4.  Conciseness (how much extraneous stuff do you have to type in)
5.  Etensibility
6.  Flexibility

Note that I am not necessarily advocating these as higher principles,
merely calling them out as possibilities for criteria that we could use
if we wanted to try to resolve this argument objectively.

Let's compare (bind (var val var val ...) ...) and LET according to
these criteria just to see how such an analysis might play out.

1.  Readability.  This is debatable.  Some people like extra parens,
others don't.  On this criteria these two are a tossup.

2.  Parsability.  Parsing BIND syntax is marginally more difficult than
parsing LET bindings, but its the difference between

(loop for (varname initvalue) in bindings ...)

and

(loop for (varname initvalue) on bindings by cddr ...)

a negligible difference.

3.  Robustness to errors.  This is probably an empirical question.  One might
argue that it's easier to lose track of where you are using BIND rather than
LET, i.e.

(bind (x y q z r s l v p ...) ...)

By the time you get around to P, is that a variable or an initialization
value for V?  It's harder to get "off track" with the redundant information
provided by the extra parens in LET:

(let ( (x y) (q z) (r s) (l v) (p ...) ...) ...)

So LET probably wins on this score.  But one could argue that it's not
a big win because most of the time you are going to have expresssions
as init-values, not variable names, so the more typical case will be

(bind (x (foo) y (baz) z (bing))

If you put all the bindings on separate lines then it's not at all clear
that the extra parens buy you much.

4.  Conciseness.  BIND (the keywordless version) wins for the same reason
it lost on robustness: fewer parens.

5.  Extensibility.  One could imagine extending LET to allow extra information
in the binding clauses, e.g.:

(let ( (x 1 integer lexical) ...) ...)

BIND could be extended the same way, but at the cost of significantly
harder parsing, so extending BIND comes at a significant cost in terms of
criterion 2.

6. Flexibility.  The keyword-optional version of BIND wins because the
user can choose if he wants to write:

(bind x = 1 and y = 2 and z = 3 in ...)

or simply

(bind x 1 y 2 z 3 in ...)

LET is slightly flexible in that you can choose to omit the parens for an
uninitialized binding.  The non-keyword BIND is completely inflexible.

I am not going to draw any conclusions because my point here is not to
defend BIND but to illustrate how a principled analysis of the relative
*syntactic* merits of such a proposal might be conducted.  I am not taking
a stand on anything, just illustrating possible alternatives to arguments
of the form, "You don't have the proper feel for S expressions."

Erann Gat
···@jpl.nasa.gov

From: Barry Margolin
Subject: Re: Evaluating syntax
Date: 
Message-ID: <ryXw4.54$eW.1405@burlma1-snr2>
In article <····················@milo.jpl.nasa.gov>,
Erann Gat <···@jpl.nasa.gov> wrote:
>5.  Extensibility.  One could imagine extending LET to allow extra information
>in the binding clauses, e.g.:
>
>(let ( (x 1 integer lexical) ...) ...)
>
>BIND could be extended the same way, but at the cost of significantly
>harder parsing, so extending BIND comes at a significant cost in terms of
>criterion 2.

LET allows you to leave out the initialization expression, i.e.

(let (x (y 1) (z (foo 'bar))) ...)

With BIND you would have to put X's inializer in explicitly:

(bind (x nil y 1 z (foo 'bar)) ...)

A criterion that you didn't mention in your list is consistency within the
language, i.e. is this syntax similar to other constructs in the language?
Throughout the language, grouping tends to be indicated by nesting rather
than alternating.  For instance, the syntax of LET bindings is similar to
that of DO bindings.

The only place where alternation tends to be used is in keyword arguments
to functions; this was modeled after arguments in OS command line
interpreters (i.e. shells) rather than other Lisp constructs.  The
distinctiveness of keyword symbols provides the visual cue needed to see
the grouping, as well as some error checking if an argument is left out.


BTW, you can get your keyword version of BIND by using LOOP:

(loop with x = 1 and y = 2 and z = 3
      return ...)

:)

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Erann Gat
Subject: Re: Evaluating syntax
Date: 
Message-ID: <gat-0703000959590001@milo.jpl.nasa.gov>
In article <················@burlma1-snr2>, Barry Margolin
<······@bbnplanet.com> wrote:

> The only place where alternation tends to be used is in keyword arguments
> to functions;

And in PLISTS.  And, as you yourself point out, in LOOP.

E.
From: Christopher R. Barry
Subject: Re: Evaluating syntax
Date: 
Message-ID: <87aekb7crh.fsf@2xtreme.net>
Barry Margolin <······@bbnplanet.com> writes:

> A criterion that you didn't mention in your list is consistency within the
> language, i.e. is this syntax similar to other constructs in the language?
> Throughout the language, grouping tends to be indicated by nesting rather
> than alternating.  For instance, the syntax of LET bindings is similar to
> that of DO bindings.
> 
> The only place where alternation tends to be used is in keyword arguments
> to functions;

[...]

What about (SETF <place-1> <val-1> <place-2> <val-2 ...) ?

Christopher
From: Barry Margolin
Subject: Re: Evaluating syntax
Date: 
Message-ID: <%vax4.7$Ag3.307@burlma1-snr2>
In article <··············@2xtreme.net>,
Christopher R. Barry <······@2xtreme.net> wrote:
>Barry Margolin <······@bbnplanet.com> writes:
>
>> A criterion that you didn't mention in your list is consistency within the
>> language, i.e. is this syntax similar to other constructs in the language?
>> Throughout the language, grouping tends to be indicated by nesting rather
>> than alternating.  For instance, the syntax of LET bindings is similar to
>> that of DO bindings.
>> 
>> The only place where alternation tends to be used is in keyword arguments
>> to functions;
>
>[...]
>
>What about (SETF <place-1> <val-1> <place-2> <val-2 ...) ?

True.  That happened for historical reasons.  Originally SETQ and SETF only
allowed one assignment, so they were just (SETF place val).  When they were
extended to allow multiple assignments, it would have caused an
incompatibility if it were changed to (SETF (place1 val1) (place2 val2)
...).

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Daniel Barlow
Subject: Re: Evaluating syntax
Date: 
Message-ID: <87put7dpnk.fsf@tninkpad.telent.net>
···@jpl.nasa.gov (Erann Gat) writes:

> 2.  Parsability.  Parsing BIND syntax is marginally more difficult than
> parsing LET bindings, but its the difference between
> 

Parseability has more than one aspect (or maybe, is more than one criterion).
In addition to how Lisp parses it, the editor gets a vote too.

For example, the extra layer of parens in a LET construct as opposed
to, say, a SETF with multiple assignations allows Emacs to be a bit
cleverer about indenting it.

Compare 

(let ((a 1)
      (b 2)
      (c
       3)
      (d
       4)
      (e 5)))

with

(setf a 1
      b 2
      c
      3
      d
      4
      e 5)

That 3 and 4 are indented relative to c and d makes it clearer which
are variables and which are values.

-dan
From: Raymond Toy
Subject: Re: Evaluating syntax
Date: 
Message-ID: <4n8zzqg8h1.fsf@rtp.ericsson.se>
>>>>> "Daniel" == Daniel Barlow <···@telent.net> writes:

    Daniel> ···@jpl.nasa.gov (Erann Gat) writes:
    >> 2.  Parsability.  Parsing BIND syntax is marginally more difficult than
    >> parsing LET bindings, but its the difference between
    >> 

    Daniel> Parseability has more than one aspect (or maybe, is more than one criterion).
    Daniel> In addition to how Lisp parses it, the editor gets a vote too.

    Daniel> For example, the extra layer of parens in a LET construct as opposed
    Daniel> to, say, a SETF with multiple assignations allows Emacs to be a bit
    Daniel> cleverer about indenting it.

    Daniel> Compare 

    Daniel> (let ((a 1)
    Daniel>       (b 2)
    Daniel>       (c
    Daniel>        3)
    Daniel>       (d
    Daniel>        4)
    Daniel>       (e 5)))

    Daniel> with

    Daniel> (setf a 1
    Daniel>       b 2
    Daniel>       c
    Daniel>       3
    Daniel>       d
    Daniel>       4
    Daniel>       e 5)

    Daniel> That 3 and 4 are indented relative to c and d makes it clearer which
    Daniel> are variables and which are values.

Makes emacs lisp indenter smarter?  

Ray
From: Robert Monfera
Subject: Re: Evaluating syntax
Date: 
Message-ID: <38C51B60.83E2670E@fisec.com>
Erann Gat wrote:

> But I have little respect for arguments from authority.  Are there
> higher principles to which we can appeal to resolve these issues?  Some
> possibilities include:
>
> 1.  Readability (how hard is it for a human to read)
> 2.  Parsability (how hard is it for a machine to read)
> 3.  Robustness to errors (how likely is it that a small lexical error
> will result in a large semantic error)
> 4.  Conciseness (how much extraneous stuff do you have to type in)
> 5.  Etensibility
> 6.  Flexibility

7. How easy it is to put together macros
Exposing the structure of LET with parentheses makes it easier.

Maybe emacs could be programmed to do to achieve what you want: a line
insertion inside two LET bindings would automatically create a pair of
parentheses and position the cursor between them.

We still have SETF, but unlike LET or BIND it does not have a body.

Robert
From: Pierre R. Mai
Subject: Re: Evaluating syntax
Date: 
Message-ID: <87ityz3vge.fsf@orion.dent.isdn.cs.tu-berlin.de>
Robert Monfera <·······@fisec.com> writes:

> Erann Gat wrote:
> 
> > But I have little respect for arguments from authority.  Are there
> > higher principles to which we can appeal to resolve these issues?  Some
> > possibilities include:
> >
> > 1.  Readability (how hard is it for a human to read)
> > 2.  Parsability (how hard is it for a machine to read)
> > 3.  Robustness to errors (how likely is it that a small lexical error
> > will result in a large semantic error)
> > 4.  Conciseness (how much extraneous stuff do you have to type in)
> > 5.  Etensibility
> > 6.  Flexibility
> 
> 7. How easy it is to put together macros
> Exposing the structure of LET with parentheses makes it easier.

8. How much of a burden you put on code walkers and other source
   walking/morphing code to parse your constructs.  E.g. writing a
   full parser for LOOP is quite a bit of work, and you are in
   constant danger of not getting it right.  Luckily for code walkers
   (though possibly not for other morphing code), LOOP is a macro, and 
   so you can just macro-expand, and get something more amenable to
   parsing (though most likely not for ananlysis).

   Complex syntax (and that includes all not fully parenthized
   constructs IMHO, i.e. all position or keyword based parsing save
   the easy endless alternation of things) in special forms, is
   much more evil.

[ Yes this could be subsumed under item 2 above, but there's a difference
  in emphasis: If something only bothers the implementor, then I
  mostly have no problem with it, as long as it's still implementable
  in with reasonable effort.  If it bothers user code, then I'm much
  more critical. ]

[ Or we could subsume points 2, 7 and 8 under the heading of
  "processability", or something to this effect.  But note that
  processability is much more important in CL with macros and code
  morphing code, than in languages like C and most other Algol
  derivates. ]

> We still have SETF, but unlike LET or BIND it does not have a body.

And even more importantly, SETF and LOOP are not special forms, unlike
LET or BIND (will have to be).  Having special forms with complex
syntax makes things that much more complex for code walkers.

And yes, once you deprecate or remove special declarations, BIND will
either have to be a special form (preferred), or will have to be a
macro that expands into something that uses implementation specific
special forms (which is very bad for code walkers).

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Tim Bradshaw
Subject: Re: Evaluating syntax
Date: 
Message-ID: <ey3sny3yovj.fsf@cley.com>
* Pierre R Mai wrote:

> And even more importantly, SETF and LOOP are not special forms, unlike
> LET or BIND (will have to be).  Having special forms with complex
> syntax makes things that much more complex for code walkers.

LET does not have to be treated as a special form in a code walker--
as far as I can see the code below implements it.

    (defmacro let ((&rest bindings) &body body)
      ((lambda (vars vals)
	 `((lambda (,@vars)
	     ,@body)
	   ,@vals))
       (mapcar (lambda (v)
		 (if (consp v)
		     (car v)
		     v))
	       bindings)
       (mapcar (lambda (v)
		 (if (consp v)
		     (cadr v)
		     nil))
	       bindings)))

(it's interesting that ACL produces bitwise-identical code for this
and LET in all the cases I tried (I'm not trying to imply they
implement it this way)).

> And yes, once you deprecate or remove special declarations, BIND will
> either have to be a special form (preferred), or will have to be a
> macro that expands into something that uses implementation specific
> special forms (which is very bad for code walkers).

I think so.

--tim
From: Barry Margolin
Subject: Re: Evaluating syntax
Date: 
Message-ID: <7yax4.8$Ag3.410@burlma1-snr2>
In article <···············@cley.com>, Tim Bradshaw  <···@cley.com> wrote:
>LET does not have to be treated as a special form in a code walker--
>as far as I can see the code below implements it.
>
>    (defmacro let ((&rest bindings) &body body)
>      ((lambda (vars vals)
>	 `((lambda (,@vars)
>	     ,@body)
>	   ,@vals))
>       (mapcar (lambda (v)
>		 (if (consp v)
>		     (car v)
>		     v))
>	       bindings)
>       (mapcar (lambda (v)
>		 (if (consp v)
>		     (cadr v)
>		     nil))
>	       bindings)))
>
>(it's interesting that ACL produces bitwise-identical code for this
>and LET in all the cases I tried (I'm not trying to imply they
>implement it this way)).

This was how LET expanded in Maclisp, but in Common Lisp I think there are
some differences having to do with scopes of declarations at the head of
the body.

If it could have been described in CLTL by equivalence with LAMBDA, I think
it would have been.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Tim Bradshaw
Subject: Re: Evaluating syntax
Date: 
Message-ID: <ey3og8qsm3o.fsf@cley.com>
* Barry Margolin wrote:

> This was how LET expanded in Maclisp, but in Common Lisp I think there are
> some differences having to do with scopes of declarations at the head of
> the body.

I'd be interested in knowing the differences (not a rhetorical
question!).

--tim
From: Barry Margolin
Subject: Re: Evaluating syntax
Date: 
Message-ID: <ZEcx4.25$Ag3.496@burlma1-snr2>
In article <···············@cley.com>, Tim Bradshaw  <···@cley.com> wrote:
>* Barry Margolin wrote:
>
>> This was how LET expanded in Maclisp, but in Common Lisp I think there are
>> some differences having to do with scopes of declarations at the head of
>> the body.
>
>I'd be interested in knowing the differences (not a rhetorical
>question!).

I'm having trouble finding specific examples, but I thought there were
cases where a declaration in a LET body would apply to the initialization
forms, not just the bound variables and the body.  If you rewrite it as an
application of a lambda expression, the initialization forms move outside
to become arguments, and can't be affected by declarations inside the
lambda.

X3J13 made some adjustments to declaration scope, so it's possible that
this is no longer true.  But I definitely remember someone like Alan Bawden
pointing it out to me in the early 80's.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Erann Gat
Subject: Re: Evaluating syntax
Date: 
Message-ID: <gat-0703001004540001@milo.jpl.nasa.gov>
In article <··············@orion.dent.isdn.cs.tu-berlin.de>, ····@acm.org
(Pierre R. Mai) wrote:

> And even more importantly, SETF and LOOP are not special forms, unlike
> LET or BIND (will have to be).  Having special forms with complex
> syntax makes things that much more complex for code walkers.

First, both LET and BIND can be implemented as macros.  In fact, I
even posted an example implementation of BIND as a macro earlier.
And you even contradict yourself later in your own post:

> BIND will
> either have to be a special form (preferred), or will have to be a
> macro

Second, as I also mentioned in my original posting on this topic,
the difference between code-walking parenthesized bindings vs.
alternating bindings is the difference between:

(loop for (var val) in bindings ...)

and

(loop for (var val) on bindings by cddr ...)

Seven extra characters to parse alternating bindings.  That investment
will pay for itself (in terms of keystrokes) after four bindings.  ;-)

E.
From: Tim Bradshaw
Subject: Re: Evaluating syntax
Date: 
Message-ID: <ey3ln3usefr.fsf@cley.com>
* Erann Gat wrote:
> First, both LET and BIND can be implemented as macros.  In fact, I
> even posted an example implementation of BIND as a macro earlier.
> And you even contradict yourself later in your own post:

It seems to me that BIND can only be implemented as a macro if there
is an alternative, primitive, way of establishing special bindings.
But I thought you were against that? Maybe I am confused though &
you're only against having global special proclamations.

--tim
From: Barry Margolin
Subject: Re: Evaluating syntax
Date: 
Message-ID: <fvex4.41$Ag3.648@burlma1-snr2>
In article <···············@cley.com>, Tim Bradshaw  <···@cley.com> wrote:
>* Erann Gat wrote:
>> First, both LET and BIND can be implemented as macros.  In fact, I
>> even posted an example implementation of BIND as a macro earlier.
>> And you even contradict yourself later in your own post:
>
>It seems to me that BIND can only be implemented as a macro if there
>is an alternative, primitive, way of establishing special bindings.
>But I thought you were against that? Maybe I am confused though &
>you're only against having global special proclamations.

BIND doesn't create special bindings specifically.  It's just like LET
except that the syntax of the variable list is different.  Instead of

(let ((var1 val1) (var2 val2) ...) ...)

it's

(bind (var1 val1 var2 val2 ...) ...)

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Tim Bradshaw
Subject: Re: Evaluating syntax
Date: 
Message-ID: <ey3aekasbfy.fsf@cley.com>
* Barry Margolin wrote:

> BIND doesn't create special bindings specifically.  It's just like LET
> except that the syntax of the variable list is different.  Instead of

> (let ((var1 val1) (var2 val2) ...) ...)

> it's

> (bind (var1 val1 var2 val2 ...) ...)

Ok, I've got the threads confused somewhere, I was confusing it with
the special-variable thread which had something called BIND (?) which
did do specials (as well as lexicals).

--tim
From: Erann Gat
Subject: Re: Evaluating syntax
Date: 
Message-ID: <gat-0703001706050001@milo.jpl.nasa.gov>
In article <···············@cley.com>, Tim Bradshaw <···@cley.com> wrote:

> * Erann Gat wrote:
> > First, both LET and BIND can be implemented as macros.  In fact, I
> > even posted an example implementation of BIND as a macro earlier.
> > And you even contradict yourself later in your own post:
> 
> It seems to me that BIND can only be implemented as a macro if there
> is an alternative, primitive, way of establishing special bindings.
> But I thought you were against that? Maybe I am confused though &
> you're only against having global special proclamations.

You're confused.

I am against

1) Global special proclamations and
2) The particular syntax used to specify local special bindings

I am more against 1 than I am against 2.

(In an attempt to avoid further confusion, the proposal I made addressed
issue 2, despite the fact that I feel less strongly about it than issue 1.
The reason I decided to make a proposal about a less important issue was
that I thought I had something new to contribute to the discussion for
that issue, and I didn't have anything new to say about the other issue
short of "Get rid of DEFVAR!" which didn't seem very likely to result in
anything positive.)

I am not against the *existence* of local special bindings.  Quite the
contrary, I like local special bindings.  I just don't like the syntax
I have to use to get them.

BTW, here is the example of how LET is (maybe) different from LAMBDA.
(Thanks to Gary Byers for digging this up for me.)

(defun foo (x)
  (let ( (x (baz x)) )
    (declare (special x))
    ...

Is the X passed in as the argument to BAZ special or not?  That is,
is the argument to baz a reference to the argument to foo or shorthand
for (symbol-value 'x)?

The fact that this situation is ambiguous is IMO more evidence that the
current design is broken and needs to be fixed.  If dynamic binding
specifications were in the lamdba list this would be completely
unambiguous:

(defun foo (x)
  (let ( ((special x) (baz x)) ) ; The argument to baz is lexical

(defun foo (x)
  (let ( ((special x) (baz (special x)) ) ; The argument to baz is special

In this case I've assumed special handling for variables whose names are
lists that start with the symbol SPECIAL, and a macro (SPECIAL X) that
expands into (symbol-value (quote x)).

Using the $ reader macro ($X --> (special X)) this looks like:

(defun foo (x)
  (let ( ($x (baz x)) ) ; Lexical argument

(defun foo (x)
  (let ( ($x (baz $x)) ) ; Dynamic argument

For those who think this looks too much like Perl we can do the following:

(set-macro-character
 #\*
 (lambda (stream c)
   (declare (ignore c))
   (let* ( (s (read stream))
           (n (symbol-name s))
           (l (length n)) )
     (if (eql (char n (1- l)) #\*)
       `(symbol-value (quote ,(intern (concatenate 'string "*" n))))
       (intern (concatenate 'string "*" n)))))
 t)

This reads symbols beginning and ending with asterisks as
(symbol-value (quote ...)).  This, together with the lambda-list
syntax extension I propose, would allow you to write:

(defun foo (x)
  (let ( (*x* (baz x)) )  ; Lexical reference, dynamic binding

(defun foo (x)
  (let ( (*x* (baz *x*)) ) ; Dynamic reference, dynamic binding

Personally I think looking a *little* more like Perl (a $little more like
Perl? :-) might not be such a bad thing from a marketing point of view.

BTW, building a semantic distinction based on symbol names into the
language itself rather than using a reader macro is not unlike the old
FORTRAN convention of making variables starting with the letters I through
N integers and all other variables reals.  It should not be hard to guess
my opinion of that idea.

E.
From: Espen Vestre
Subject: Re: Evaluating syntax
Date: 
Message-ID: <w67lfdyh5d.fsf@wallace.nextel.no>
···@jpl.nasa.gov (Erann Gat) writes:

> Personally I think looking a *little* more like Perl (a $little more like
> Perl? :-) might not be such a bad thing from a marketing point of view.

I think that's a very bad idea, since it would just confuse those used
to perl.  After all, perl uses $ both with special ("local") and
lexical ("my") variables!

And perl, with its version hell (since so much change from v. 5.003 to
5.004 to 5.005, people running big websites are really frustrated,
have to keep x versions around and keep their default perl to still be
the old 5.003) and ugly syntax, can safely be left alone with its mess.

I'm not as worried about the 'special problem' as you are.  By
adhering to the 'everything special in stars' rule, I haven't
really encountered problems.

-- 
  (espen)
From: Pierre R. Mai
Subject: Re: Evaluating syntax
Date: 
Message-ID: <87ya7u2ps4.fsf@orion.dent.isdn.cs.tu-berlin.de>
···@jpl.nasa.gov (Erann Gat) writes:

> In article <··············@orion.dent.isdn.cs.tu-berlin.de>, ····@acm.org
> (Pierre R. Mai) wrote:
> 
> > And even more importantly, SETF and LOOP are not special forms, unlike
> > LET or BIND (will have to be).  Having special forms with complex
> > syntax makes things that much more complex for code walkers.
> 
> First, both LET and BIND can be implemented as macros.  In fact, I

I'm not certain about LET, because it might well be that you could
write a macro that _correctly_ implements LET in terms of other ANSI
CL special operators (together with LAMBDA), though I think you'd have
to be fairly careful not to miss subtle differences in scoping of
declarations etc. (See also Barry Margolin's postings in this thread).

But that's beside the point, since LET is defined as a special operator
in the standard, and so any portable code-walker will have to be able
to handle it specially anyway.

WRT to bind:

> even posted an example implementation of BIND as a macro earlier.

Yes, you did, but we are not talking about BIND in the context of ANSI 
CL _now_ (at least I think we aren't), we are talking about an ANSI
CL, where BIND and modified lambda-lists will be the only way to bind
special variables, as per your proposal.

In this context either you can come up with a good macro that implements
bind for both lexical and dynamic (and what else) variables correctly
_and efficiently on all platforms_ in terms of your modified lambda,
or BIND will have to be declared a special operator, to allow
implementations to do this stuff efficiently themselves.

Letting BIND expand into implementation-specific special forms although
technically possible is not an option, because this will make it nearly
impossible to write portable code-walkers.

Given that your macro used special declarations internally, in a future
ANSI CL this would be tantamount to using implementation-specific special
forms, and so your BIND macro doesn't count ;)

> And you even contradict yourself later in your own post:
> 
> > BIND will
> > either have to be a special form (preferred), or will have to be a
> > macro

If you hadn't snipped to early, you would have left in the gotcha:

The apparent contradiction is the one between technical possibility
(yes you can do things like expanding into "secret" special forms), 
and standards design criteria (this shouldn't be endorsed, because it
has obvious draw-backs for all code-walkers).  This is why BIND could
technically be a MACRO, but because of the draw-backs involved it
would "have to be" a special operator.

> Second, as I also mentioned in my original posting on this topic,
> the difference between code-walking parenthesized bindings vs.
> alternating bindings is the difference between:
> 
> (loop for (var val) in bindings ...)
> 
> and
> 
> (loop for (var val) on bindings by cddr ...)
> 
> Seven extra characters to parse alternating bindings.  That investment
> will pay for itself (in terms of keystrokes) after four bindings.  ;-)

I thought we were talking about BIND as in your original proposal,
i.e. with LOOP-like (in your case optional) keyword syntax.  That
requires more than simply changing from alternating to nesting or
vice-versa.  That's what I'm objecting to.

I don't have any objections to alternating style special forms (we
have setq, and little problems with it) on the grounds of computer
parsability.  I think that in binding constructs, as opposed to
setting constructs, the extra level of nesting has a nice mnemonic
touch (it binds the value to the variable), and also helps human
readability, since it's much more common to bind many variables than
it is to set more than one or two variables.  But that has nothing
to do with parsing.

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Tom Breton
Subject: Re: Evaluating syntax
Date: 
Message-ID: <m3g0u2nl05.fsf@world.std.com>
···@jpl.nasa.gov (Erann Gat) writes:

> In a recent posting I proposed a macro called BIND that allows you to
> write code that looks like:
> 
> (bind x = 1 and y = 2 in
>   (foo x y))
> 
> instead of
> 
> (let ( (x 1) (y 2) )
>   (foo x y))
> 
> Some people objected to this macro on the grounds that it violated the
> spirit of S-expressions.  For example, Tom Breton wrote:
> 
> > I don't think you have the feel for sexps.  Sticking parens around
> > something may technically make it a sexp, but it doesn't make it a
> > tolerable one.  A sexp should not have internal dependencies.  IMO
> > even boa parameter lists are iffy.
> 
> All this led me to think about what is the true spirit of S-expressions.
> John McCarthy himself once wrote that there were too many parentheses
> in the COND macro, and that's about as strong an authority as it gets
> in this game.  
>
> So the following would be OK according to McCarthy:
> 
> (cond condition action condition action ...)
> 
> instead of
> 
> (cond (condition action) (condition action) ...)

If it is an accurate reflection of his overall views, which I doubt,
I'd just disagree with him.  Parentheses are cheap, for all practical
purposes they're free.  IMO, use them anywhere they help organize
code.
 
> In the case of COND the extra parens actually do serve a purpose,
> albeit a minor one: they save you the trouble of having to put in an
> explicit PROGN in order to have multi-statement actions.  

Sorry, that's not why.  They help organize the code.  I write all
sorts of macros that use cond, and I basically just write (mapcar
...), or more often, ",@".

(If typing it in bugs you, use emacs' skeleton.el)

[Remainder snipped.  We seem to have no common ground for agreement]

-- 
Tom Breton, http://world.std.com/~tob
Not using "gh" since 1997. http://world.std.com/~tob/ugh-free.html
Rethink some Lisp features, http://world.std.com/~tob/rethink-lisp/index.html
From: Scott L. Burson
Subject: Re: Evaluating syntax
Date: 
Message-ID: <38D6B766.6526D08E@my-dejanews.com>
Erann Gat wrote:
> 
> In a recent posting I proposed a macro called BIND that allows you to
> write code that looks like:
> 
> (bind x = 1 and y = 2 in
>   (foo x y))
> 
> instead of
> 
> (let ( (x 1) (y 2) )
>   (foo x y))
> 
> Some people objected to this macro on the grounds that it violated the
> spirit of S-expressions.

I feel that way.  I've always detested LOOP, and refuse to use it.  "Making Lisp
look like Cobol" has been heard to escape my lips on occasion.  But it has a lot
of fans.  To each its own.

As for the parens in LET being redundant, I have a macro I like to use called
NLET, which expands the syntax of LET in ways that I have found useful:

  (nlet ((x y z (foo))) . body)

is equivalent to

  (multiple-value-bind (x y z) (foo) . body)

This is handy because I like to write code with lots of multiple values.  Also,
for instance,

  (nlet ((b (foo a))
         ((c (bar b))))
    . body)

is equivalent to

  (let* ((b (foo a))
         (c (bar b)))
    . body)

That's not very interesting in itself, but more complex examples can be built
that show the power of the idea:

  (nlet ((b (foo a))
         (c (bar a))
         ((d (zot b c))
          (e (zot c b))
          ((f g (quux b c d e))))
         (h (mumble)))
    . body)

which binds B, C, and H in parallel, then D and E in parallel, then finally F
and G.  The rule is that all bindings at each depth are made in parallel.  The
point of moving H's clause to the bottom like that is just readability --
related clauses can be kept together, and (unlike with LET*) the dependence
graph can be made very clear.

So on the one hand you can certainly say that LET has redundancy in its syntax
that could in principle be removed.  But my preference, as you see, is to extend
the syntax to be more useful (and no longer redundant) rather than to strip out
the redundancy.

BTW, if anyone wants this macro, I'm happy to provide it.  But there's a caveat:
I've never bothered to make it handle declarations correctly (which, as you can
see, will be a bit of a job).  Alas, that's probably the biggest reason I
haven't tried to disseminate it more widely.

-- Scott