Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PROGN considered intrusive?

36 views
Skip to first unread message

Erik Naggum

unread,
Mar 21, 1999, 3:00:00 AM3/21/99
to
there have been strong arguments against IF (and WHEN and UNLESS) here
and elsewhere, and they continue to baffle me. today, it dawned on me
that maybe what people actually don't like is PROGN. (I have never been
bothered by it any more than I'm bothered by the need to use braces
around compound statements in C, which also seems to bother some people.)

one suggested way to get rid of the PROGN is to create a new form IF*,
which takes keywords THEN and ELSE that delimit the compound statements,
and which supposedly allows more reasonable nesting, as well.

however, if PROGN is intrusive in IF, and we're relieved of its presence
in a lot of other forms which take implicit PROGNs, perhaps we should fix
PROGN, not IF? here's a suggestion:

(defun \{-reader (stream character)
(declare (ignore character))
(cons 'progn (read-delimited-list #\} stream t)))

(set-macro-character #\{ #'\{-reader)
(set-syntax-from-char #\} #\))

(set-pprint-dispatch '(cons (eql progn))
(lambda (stream object)
(pprint-logical-block (stream object :prefix "{" :suffix "}")
(pprint-linear stream object nil))))

so instead of the standard Common Lisp

(if (foo)
(progn
(then-1)
(then-2))
(progn
(else-1)
(else-2)))

we could have

(if (foo)
{(then-1)
(then-2)}
{(else-1)
(else-2)})

as opposed to the more "alternative"

(if* (foo)
then (then-1)
(then-2)
else (else-1)
(else-2))

I could easily get used to the {} forms (please don't use my C history
against me, and don't you _dare_ use whitespace after { or before }),
while I continue to have serious readability problems with the IF* form.
the reason may be that the keywords are _far_ too prominent and intrusive
compared to the forms in each branch, and much more than PROGN could ever
hope to be.

do people actually think PROGN is intrusive and a waste of space? would
using a short-hand like {} work as well to reduce "noise" as using '
instead of a QUOTE form does? and does this make more sense than IF*?

#:Erik

Johan Kullstam

unread,
Mar 21, 1999, 3:00:00 AM3/21/99
to
Erik Naggum <er...@naggum.no> writes:

> there have been strong arguments against IF (and WHEN and UNLESS) here
> and elsewhere, and they continue to baffle me. today, it dawned on me
> that maybe what people actually don't like is PROGN. (I have never been
> bothered by it any more than I'm bothered by the need to use braces
> around compound statements in C, which also seems to bother some
> people.)

> do people actually think PROGN is intrusive and a waste of space? would


> using a short-hand like {} work as well to reduce "noise" as using '
> instead of a QUOTE form does? and does this make more sense than
> IF*?

imho there's nothing wrong with progn. the tricky part is remembering
what places take a single expression and what places can take a series
of them. neither progn nor {} can help that. you just need to learn
where to do what.

the then else thing is clearly the worst as it only fixes if. aren't
there are other places where you need progn?

--
J o h a n K u l l s t a m
[kull...@ne.mediaone.net]
Don't Fear the Penguin!

Tim Bradshaw

unread,
Mar 21, 1999, 3:00:00 AM3/21/99
to
Erik Naggum <er...@naggum.no> writes:

> do people actually think PROGN is intrusive and a waste of space? would
> using a short-hand like {} work as well to reduce "noise" as using '
> instead of a QUOTE form does? and does this make more sense than IF*?
>

Perhaps what is difficult is the fact that some forms in CL have an
implicit PROGN, and it is difficult to remember which ones? C is
almost more consistent (I think) in needing to have an explicit block
in most places (though can you always leave out the block if you have
only one statement, like in a function:

int foo (int i, int j)
i + j;

I think you *can* do this in BCPL but suspect you can't in C?).

Because languages like C have nop macro facility to speak of, the language
designer then gets to decide once & for all how this should work, whereas
in Lisp, different people come along and invent various macros with
differing conventions, so it is harder perhaps.

In any case I'm against using another sort of brackets because it's nice
to leave as many as possible for user extensions. Perhaps PROGN is a bad
name -- BLOCK would be better (but already used of course). I have no
problem with PROGN in any case.

--tim

Martti Halminen

unread,
Mar 21, 1999, 3:00:00 AM3/21/99
to
Erik Naggum wrote:
>
> there have been strong arguments against IF (and WHEN and UNLESS) here
> and elsewhere, and they continue to baffle me.

Either you are referring to a longer time than I've been reading c.l.l,
or you are reading some statements in some newbie threads more seriously
than I did.

> today, it dawned on me
> that maybe what people actually don't like is PROGN.

Last I checked, WHEN and UNLESS had implicit PROGN, so
if anybody has a problem with them, it's probably not the same as with
IF.

<snip>


> so instead of the standard Common Lisp
>
> (if (foo)
> (progn
> (then-1)
> (then-2))
> (progn
> (else-1)
> (else-2)))
>
> we could have
>
> (if (foo)
> {(then-1)
> (then-2)}
> {(else-1)
> (else-2)})

Personally I dislike this idea due to bad readability: with my bad
eyesight the difference between () and {} is too small to be easily
distinguishable in the standard fonts used on this machine. (yeah, I
know I should get new glasses...)


> do people actually think PROGN is intrusive and a waste of space? would
> using a short-hand like {} work as well to reduce "noise" as using '
> instead of a QUOTE form does? and does this make more sense than IF*?

Whenever the PROGNs start to annoy me, I find myself converting the code
to use COND or CASE, instead of IF. As I often write stuff with multiple
branches, anyway, I don't have major problems with that.


--

Vassil Nikolov

unread,
Mar 21, 1999, 3:00:00 AM3/21/99
to
In article <31310128...@naggum.no>,
Erik Naggum <er...@naggum.no> wrote:
(...) ;see original posting for the details

> do people actually think PROGN is intrusive and a waste of space?
> would using a short-hand like {} work as well to reduce "noise" as
> using ' instead of a QUOTE form does?
> and does this make more sense than IF*?

(0) I have no problems with PROGN and, as another poster wrote, if
I happen to be reluctant to write ``(IF ... (PROGN ...) ...)''
(which usually I am not), there's COND.

(1) I would have problems with IF* (or however one might call it).
(I have the same (psychological) problems with LOOP---with all
these deparemthesised keywords its syntax appears `brittle'
to me, so personally I find its use justified only when it
offers useful functionality in simple syntax, like COLLECT,---
when things get more complicated with a DO.) If we _must_ have
an if with implicit progns, I'd rather have it this way:
(IF+ test (then-progn-body) [ (else-progn-body) ])
i.e. adding two extra pairs of parentheses than adding
keywords. I am not saying that we should have such an if;
I'm just saying ``(IF* ... THEN ... ELSE ...)'' is worse IMO.

(2) I don't have problems remembering which forms allow an
implicit progn. Correct me if I'm wrong---I am too lazy to
check all special forms and macros now---but I think all CL
forms that could have an implicit progn in the body do so.
IF obviously couldn't. (It is more difficult for me to
remember which bodies are implicit progns, which are blocks,
and which are tagbodies, but I can easily remember that loops
are nameless blocks, function bodies are named blocks, and for
the rest I don't mind looking it up if I happen to need it.)

(3) As to finding a more economical syntax for PROGN, there are
obviously two questions here: do we need one, and if yes, what.
I can't say if we do (I don't, but I can't speak for anybody
else). Assuming we do, I support the objection against {}
that has already been raised, namely, why waste the braces
as macro characters reserved for the user. (I don't mind the
C-like syntax that would result... though a compound statement
in C doesn't return a value.) Besides, all forms in Common Lisp
that are not atoms start and end in parentheses^1; why introduce an
exception? So, instead of {}, why not define a macro called @
such that (@ ...) -> (PROGN ...) (why @? Because it will be
followed by a list of forms and thus there is some analogy to ,@).
Or modify the reader so that ``(. body)'' is read as ``(PROGN body)''
(e.g. by modifying the lparen reader to treat a dot followed by a
non-consituent specially).
__________________________
^1 This is a lie of course. But #', ', and ` all mean that something
special is taking place with regards to evaluation (that the following
form is a constant or quasi-constant, as it were), which is rather
different from the kind of form that PROGN is.

My point is really not that ``(@ ...)'' or ``(. ...)'' are good
but that maybe we don't really need ``{...}'' (and that is what
my personal experience shows: it did occur to me many years ago
to define {} to read as a PROGN form, and I did have enough free
time to do it, but I never considered it really important).

In any case, {} makes more sense than IF* to me. (I might use {}
but I wouldn't use IF*.)

FWIW (2e-2?)

Vassil Nikolov <vnik...@poboxes.com> www.poboxes.com/vnikolov
(You may want to cc your posting to me if I _have_ to see it.)
LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Erik Naggum

unread,
Mar 22, 1999, 3:00:00 AM3/22/99
to
* Sam Steingold <s...@goems.com>
| - you are trying to solve an imaginary problem (most problems with
| syntax are such);

false. I'm working with huge amounts of code with the IF* macro, because
the author thinks IF, WHEN and UNLESS suck, big time.

| IIRC, the FAQ suggests using COND instead of IF/PROGN.
| That's what I do.

OK, so I forgot to mention the gripes with COND, too.

#:Erik

Erik Naggum

unread,
Mar 22, 1999, 3:00:00 AM3/22/99
to
* Vassil Nikolov <vnik...@poboxes.com>

| I would have problems with IF* (or however one might call it). (I have
| the same (psychological) problems with LOOP---with all these
| deparenthesised keywords its syntax appears `brittle' to me, so

| personally I find its use justified only when it offers useful
| functionality in simple syntax, like COLLECT,--- when things get more
| complicated with a DO.)

I happen to like IF and (extended) LOOP, but the curious thing is that
the proponents of IF* hate (extended) LOOP. I actually have a very hard
time understanding the arguments in favor of IF* (it actually expands
into a COND which I find very readable, in particular after teaching the
pretty printer to indent the body of clause two more spaces), and I have
a very hard time reading IF* code trying to figure out what happens with
with THENRET, ELSEIF, and whatnot, but not with the COND expansion.

however, there is probably a real concern somewhere in there (despite the
"I don't _want_ to like IF, WHEN, UNLESS, or COND!" it sounds like), and
I thought maybe it could have been PROGN. the important thing is that
there's a culture of IF* users that I'd _like_ to work with, but I'm
getting overpowering urges to fix it all the time when I look at such
code. so I was appealing to the general Lisp community for a means to
solve an underlying problem, which would remove or seriously weaken the
rationale for IF*.

| ... I think all CL forms that could have an implicit progn in the body do


| so. IF obviously couldn't.

well, not that this is important, but IF _could_ take an implicit PROGN
in the else part. MACLISP did, and Emacs Lisp (consequently) does.

| In any case, {} makes more sense than IF* to me. (I might use {} but I
| wouldn't use IF*.)

FWIW, thanks.

#:Erik

Jussi Piitulainen

unread,
Mar 22, 1999, 3:00:00 AM3/22/99
to
Tim Bradshaw <t...@tfeb.org> writes:

> In any case I'm against using another sort of brackets because it's
> nice to leave as many as possible for user extensions. Perhaps
> PROGN is a bad name -- BLOCK would be better (but already used of
> course). I have no problem with PROGN in any case.

Another fully parenthesised language calls it BEGIN. On an April
Fool's day, a notable practitioner in that language proposed the
addition of an optional END so that one could write

(BEGIN
form1
form2
form3
END).

The proposal was not adopted, if I recall correctly.
--
Jussi

Vassil Nikolov

unread,
Mar 22, 1999, 3:00:00 AM3/22/99
to
In article <31310626...@naggum.no>,
Erik Naggum <er...@naggum.no> wrote:
> * Vassil Nikolov <vnik...@poboxes.com>
(...)

It would have been interesting to me to read insights on the need for
IF* by someone who developed it, but I can't force it.

> | IF obviously couldn't [have an implicit progn in the body].


>
> well, not that this is important, but IF _could_ take an implicit PROGN
> in the else part. MACLISP did, and Emacs Lisp (consequently) does.

Yes, of course.

I just did not want to be too verbose. I don't accept an implicit PROGN
in the else part only, not because it is syntactically impossible (it is
possible, of course), but because such asymmetry between the then and
else parts is a bad thing IMO. It could also lead to the bad programming
practice of inverting the test just to get a progn capability for the
branch where one wants it more badly (I am theorising here, I don't
know if this actually happened with MACLISP users or happens with Emacs
Lisp users).

Or would an implicit progn for the else part serve as a sort of
compensation for its being optional? IF as an equal opportunities
special form...

(See? I _know_ it's better when I try not to be verbose, but I
don't always manage...)

> | In any case, {} makes more sense than IF* to me. (I might use {} but I
> | wouldn't use IF*.)
>
> FWIW, thanks.

No sweat!

By the way, I forgot to add last night that if someone is eager to
develop {} syntax, they might as well consider doing more with it,
like making it a block if the first thing after the open brace is
a symbol (to serve as the name of the block), and possibly a loop
if some additional magic character appears somewhere.
(I wonder, would it be easier for me to handle extended LOOP
syntax if it was surrounded by {} rather than by ()? What a
difference a couple of folds in a curve may make...)

I mean things like:

{foo ;this is (block foo ...)
(bar baz)
(when quux (return-from foo quuuuux))
(etc) #<where do I put the closing brace now???>

;; trailing star is supposed to make this a loop:
;; (pick up any other strange syntax you like)
{for i = 0 to (- n 1) do (print i)}*

and I don't mean `this should be done,' just `don't forget I
suggested it'...

Sunil Mishra

unread,
Mar 22, 1999, 3:00:00 AM3/22/99
to
Vassil Nikolov <vnik...@poboxes.com> writes:

> By the way, I forgot to add last night that if someone is eager to
> develop {} syntax, they might as well consider doing more with it,
> like making it a block if the first thing after the open brace is
> a symbol (to serve as the name of the block), and possibly a loop
> if some additional magic character appears somewhere.
> (I wonder, would it be easier for me to handle extended LOOP
> syntax if it was surrounded by {} rather than by ()? What a
> difference a couple of folds in a curve may make...)
>
> I mean things like:
>
> {foo ;this is (block foo ...)
> (bar baz)
> (when quux (return-from foo quuuuux))
> (etc) #<where do I put the closing brace now???>
>
> ;; trailing star is supposed to make this a loop:
> ;; (pick up any other strange syntax you like)
> {for i = 0 to (- n 1) do (print i)}*
>
> and I don't mean `this should be done,' just `don't forget I
> suggested it'...

Excuse me, but *gag*

Seriously, a great thing about lisp is that there is only one *delimiting*
syntax - (). (Yes, there are other parts of the syntax, such as , and ' and
`, but they are not syntactic delimiters.) Now, if you throw in a {} pair
as well, it will take that much more effort to read lisp syntax. Suddenly
you would have to pay attention to the particular delimiter, and not just
the fact that it is a delimiter. It is an additional load I don't really
care to have. At first I didn't like the fact that ' and ` are so similar
either, but the effect they have is similar enough that it does not bother
me that much. But ( and { appear to have distinct enough semantic
properties that I may never ease into this syntax. Add to that the fact
that in some fonts on some displays { and ( don't look all that
different...

Finally, as to the {}* syntax, I would much rather have something like
{* ... }. That way at least you know up front that it is a loop, rather
than having to wait upto the end to find out that it is a loop and then
having to reparse the code. Much more in keeping with the usual lisp
syntax, IMHO.

Sunil

David B. Lamkins

unread,
Mar 22, 1999, 3:00:00 AM3/22/99
to
In article <efyyakp...@whizzy.cc.gatech.edu> , Sunil Mishra
<smi...@whizzy.cc.gatech.edu> wrote:

[snip]

> Seriously, a great thing about lisp is that there is only one *delimiting*
> syntax - (). (Yes, there are other parts of the syntax, such as , and ' and
> `, but they are not syntactic delimiters.) Now, if you throw in a {} pair
> as well, it will take that much more effort to read lisp syntax. Suddenly
> you would have to pay attention to the particular delimiter, and not just
> the fact that it is a delimiter. It is an additional load I don't really
> care to have.

Yup. Who remembers the "super-parens" [ and ] that were so popular some
years ago. And how often do you see them now? (The last place I saw them
enshrined in the environment was in the old ACL/Windows 3.0, a system that
dates back... I'm not sure, maybe 7 to 10 years.

I guess they were an interesting intellectual exercise in syntax (re)design.
But the benefit apparently wasn't worth the extra effort of remembering how
to use them.

[snip]

--
David B. Lamkins <http://www.teleport.com/~dlamkins/>

Arthur Lemmens

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to

I don't think that using {...} or THEN/ELSE instead of (PROGN ...)
solves anything. At least not for me.

But I could imagine some kind of big BRANCH (or SWITCH or DISPATCH or
MATCH or whatever) macro that generalizes IF, COND, WHEN, UNLESS, CASE
and various less standardized macros like WHEN-LET (Lispworks), AIF, and
AWHEN (Paul Graham in "On Lisp"). Maybe even some simple pattern
matchers.

Just like LOOP generalizes DO, DOLIST, DOTIMES, MAPCAR, MAPC, etcetera.

When I started learning modern Common Lisp, LOOP seemed so complicated
to me and the use of non-parenthesized clauses so counter-intuitive that
I tended to avoid it.
After all, why use:
(LOOP FOR I FROM 0 TO (- N 1)
DO ...)
when you could just as easily write:
(DOTIMES (I N)
...)
Or
(LOOP FOR X IN LIST
COLLECT ...)
when you can use:
(MAPCAR (LAMBDA (X) ...)
LIST)

Now that I understand LOOP a bit better, I know why it's often better
to use LOOP (although I still don't like the syntax):

it's more resistant to change.

It captures the essence of what you want to do: you want to loop.
Right now, you may think that you just need to transform the elements
of a list, and MAP may work just as well as LOOP. But in a later stage
you may discover that you don't just want to transform the elements, you
also want to count them. If you'd used LOOP from the beginning, you
would
just add an extra clause. But if you'd used MAP, you would have to wrap
a
LET around it and insert an INCF inside the LAMBDA.

Something similar may apply to the many variants of COND. Somewhere in
the Platonic universe, there's probably a special form that captures the
essence of many different ways of branching.

Erik Naggum wrote:

> so I was appealing to the general Lisp community for a means to
> solve an underlying problem, which would remove or seriously
> weaken the rationale for IF*.

I don't know the IF* macro you're referring to (would appreciate a
reference). But maybe the solution is not to weaken the rationale
for IF*, but to create an IF* with a better rationale. Don't make a
weaker IF* (like your PROGN-hack), but make a stronger one.

No, I don't have any concrete proposals. Just brainstorming.
(As a matter of fact, I would be very surprised if this particular
brainstorm weren't a deja vu for the more experienced readers of
comp.lang.lisp.)

Arthur Lemmens


Rob Warnock

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
David B. Lamkins <dlam...@teleport.com> wrote:
+---------------

| Yup. Who remembers the "super-parens" [ and ] that were so popular some
| years ago. And how often do you see them now?
+---------------

MzScheme treats [...] as identical to (...), except you have to match the
closing kind with the opening kind, and I've seen a bunch of MzScheme code
that uses the square versions to (try to) make reading multiple levels of
parens easier in forms like case/cond/let/etc.:

; snippet from mzscheme/collects/standard/dater.ss
(cond
[(and (= month 2) (leap-year? year)) 29]
[(= month 2) 28]
[(<= month 7) (+ 30 (modulo month 2))]
[else (+ 30 (- 1 (modulo month 2)))])

or:

(letrec ([odd? (lambda (x) (if (zero? x) #f (even? (1- x))))]
[even? (lambda (x) (if (zero? x) #t (odd? (1- x))))])
...body...)

Personally, I don't like the style, since I've gotten used to relying
on a paren-matching editor and indenting, which lets me totally ignore
the closing brackets. And having a right bracket show up in the middle
of a run of right parens (as in the last line of the first example or
the next-to-last of the second) is, well, a bit jarring. But YMMV...


-Rob

-----
Rob Warnock, 8L-855 rp...@sgi.com
Applied Networking http://reality.sgi.com/rpw3/
Silicon Graphics, Inc. Phone: 650-933-1673
2011 N. Shoreline Blvd. FAX: 650-964-0811
Mountain View, CA 94043 PP-ASEL-IA

paul_...@scientia.com

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
In article <36F6CC00...@simplex.nl>,
Arthur Lemmens <lem...@simplex.nl> wrote:

> Now that I understand LOOP a bit better, I know why it's often better
> to use LOOP (although I still don't like the syntax):
>
> it's more resistant to change.
>
> It captures the essence of what you want to do: you want to loop.
> Right now, you may think that you just need to transform the elements
> of a list, and MAP may work just as well as LOOP. But in a later stage
> you may discover that you don't just want to transform the elements, you
> also want to count them. If you'd used LOOP from the beginning, you
> would
> just add an extra clause. But if you'd used MAP, you would have to wrap
> a
> LET around it and insert an INCF inside the LAMBDA.
>

To some degree these things are a matter of taste so there's little point
arguing about them, but I'll have a go anyway :-)

One of the most important qualities code, particularly code that forms part
of large software systems that will at some point be maintined by someone
other than the author, is that it's easily comprehensible. Using dolist,
mapc, mapcar when approriate rather than loop immediately gives someone a
hand in understanding what's going on. If you see mapc you know something is
being done for it's side-effects; if you see mapcar you know that the return
value is important.

Secondly I do believe that an essentially functional style make for more
comprehsible code in any case. With things like do and loop it's (relatively)
difficault to see what values are being manipulated and whether there is a
return value that is being used.

(Of course this may all be a self-serving justification for the fact that I
haven't yet got round to learning loop in all it's glory yet :-))

Kellom{ki Pertti

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
In article <7d7726$h...@fido.engr.sgi.com> rp...@rigden.engr.sgi.com (Rob Warnock) writes:
I've seen a bunch of MzScheme code
that uses the square versions to (try to) make reading multiple levels of
parens easier in forms like case/cond/let/etc.:
[...]

having a right bracket show up in the middle
of a run of right parens is, well, a bit jarring.

Square brackets are often used in method definitions in MzScheme, and
for some peculiar reason I prefer

[foo
(lambda (x)
"FOO")
]

over

[foo
(lambda (x)
"FOO")]

However, I would not dream of writing

(foo
(lambda (x)
"FOO")
)
--
Pertti Kellom\"aki, Tampere Univ. of Technology, Software Systems Lab

Arthur Lemmens

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to

I wrote:
> I know why it's often better to use LOOP [...]:

> it's more resistant to change.

paul_...@scientia.com replies:


> Using dolist, mapc, mapcar when approriate rather than loop immediately
> gives someone a hand in understanding what's going on. If you see mapc
> you know something is being done for it's side-effects; if you see mapcar
> you know that the return value is important.

Yes.

These are two sides of the same coin: dolist etc. are _more specific_
than loop (just like when etc. are more specific than cond). That can
make dolist easier to understand; it also makes it harder to change.

So maybe the choice (dolist vs. loop, when vs. cond, ...) should depend
on the kind of code you're writing. Use the more general facility
when you're not very sure of your code; use the more specific facility
when you're quite sure the code is not going to change anymore.
For my own programs, this heuristic makes the choice rather easy ;-)


Paul writes:
> To some degree these things are a matter of taste

Maybe. But taste also depends on experience.


> so there's little point arguing about them, but I'll have a go anyway :-)

Thanks for your reaction.


Arthur Lemmens


Dorai Sitaram

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
In article <7d7726$h...@fido.engr.sgi.com>,

Rob Warnock <rp...@rigden.engr.sgi.com> wrote:
>
>MzScheme treats [...] as identical to (...), except you have to match the
>closing kind with the opening kind, and I've seen a bunch of MzScheme code

>that uses the square versions to (try to) make reading multiple levels of
>parens easier in forms like case/cond/let/etc.:
>
>Personally, I don't like the style, since I've gotten used to relying
>on a paren-matching editor and indenting, which lets me totally ignore
>the closing brackets. And having a right bracket show up in the middle
>of a run of right parens (as in the last line of the first example or
>the next-to-last of the second) is, well, a bit jarring. But YMMV...

I have stopped using "syntax-highlighting" brackets in
the interest of portability. But I'll admit to liking
the fact that since braces and brackets are already
being used in _some_ Schemes for "mere" syntax
highlighting, they can't be exploited for introducing
meaningful new syntax. (Cf. letter case.)

--d

Jeffrey Mark Siskind

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
> +---------------
> | Yup. Who remembers the "super-parens" [ and ] that were so popular some
> | years ago. And how often do you see them now?
> +---------------
>
> MzScheme treats [...] as identical to (...), except you have to match the
> closing kind with the opening kind,

I think he was refering to [ and ] in Interlisp. Which is different than how
MzScheme (and other Schemes) treat [ and ]. Interlisp ] meant close all
outstanding ( up until you reach a [ or the top level if there is no [. So in
Interlisp, parentheses and brackets didn't have to match. Personally, I found
this style ugly. But there were diehard adherents. And it was useful in the
days of ASR33 TTYs before parentheses matching editors. Later, some versions
of Emacs had a keybinding for ] that would insert enough ) to close all open
(. Or some such.

Please no flames. I'm just reporting history for those too young to remember.
:-(

Jeff (http://www.neci.nj.nec.com/homepages/qobi)

Mike McDonald

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
In article <7d7j9g$ca9$1...@nnrp1.dejanews.com>,

paul_...@scientia.com writes:
> In article <36F6CC00...@simplex.nl>,
> Arthur Lemmens <lem...@simplex.nl> wrote:
>
>> Now that I understand LOOP a bit better, I know why it's often better
>> to use LOOP (although I still don't like the syntax):

> To some degree these things are a matter of taste so there's little point


> arguing about them, but I'll have a go anyway :-)
>

> One of the most important qualities code, particularly code that forms part
> of large software systems that will at some point be maintined by someone

> other than the author, is that it's easily comprehensible. Using dolist,


> mapc, mapcar when approriate rather than loop immediately gives someone a
> hand in understanding what's going on. If you see mapc you know something is
> being done for it's side-effects; if you see mapcar you know that the return
> value is important.

That's precisely why I like loop over map*, do*, ... I can never remember
what all the variations of map do. To me, loop is more explicit about what
it's doing.

Mike McDonald
mik...@mikemac.com

Christopher R. Barry

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
Erik Naggum <er...@naggum.no> writes:

[...]


> so instead of the standard Common Lisp
>
> (if (foo)
> (progn
> (then-1)
> (then-2))
> (progn
> (else-1)
> (else-2)))
>
> we could have
>
> (if (foo)
> {(then-1)
> (then-2)}
> {(else-1)
> (else-2)})
>

> as opposed to the more "alternative"
>
> (if* (foo)
> then (then-1)
> (then-2)
> else (else-1)
> (else-2))
>

> I could easily get used to the {} forms [...]

FWIW, here's my take on this. People have already complained about
using the user-reserved "{" and "}", and this would for example make
Kelly Murray's NiCLOS (Nickel-CLOS? Bad joke - Sorry, had to. Makes me
think of batteries.) macro syntax break. Though of course, his
macro-syntax could be equally said to break your proposed IF*
syntax. So let's not go there.

My proposal for IF* would be to do what the rest of Common Lisp does
with things like DO or LOGICAL-PATHNAME-TRANSLATIONS when it wants an
implicit PROGN but can't get it: use lists within lists.

(if* (foo)
((then-1)
(then-2))
((else-1)
(else-2)))

You could also do it the next way, though I don't like it as much, but
maybe it has more "consistency", especially if you hate using OR in
condition clauses:

(if* ((cond-1)
(cond-2))
((then-1)
(then-2))
((else-1)
(else-2)))

I would certainly use the former. I might even get around to writing
it and trying it out later today.

Christopher

Christopher R. Barry

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
cba...@2xtreme.net (Christopher R. Barry) writes:

[...]


> My proposal for IF* would be to do what the rest of Common Lisp does
> with things like DO or LOGICAL-PATHNAME-TRANSLATIONS when it wants an
> implicit PROGN but can't get it: use lists within lists.
>
> (if* (foo)
> ((then-1)
> (then-2))
> ((else-1)
> (else-2)))

Scratch that. It was mentioned that older Lisps gave you an implicit
PROGN for the else clause, and this is actually more like how DO is
to. So make that:

(if* (foo)
((then-1)
(then-2))
(else-1)
(else-2))

Yes, I think we've got the One True IF* form now.

Christopher

Kelly Murray

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
Christopher R. Barry wrote:
>
> Erik Naggum <er...@naggum.no> writes:
> ...
> > I could easily get used to the {} forms [...]
>
> FWIW, here's my take on this. People have already complained about
> using the user-reserved "{" and "}", and this would for example make
> Kelly Murray's NiCLOS (Nickel-CLOS? Bad joke - Sorry, had to. Makes me
> think of batteries.) macro syntax break. Though of course, his
> macro-syntax could be equally said to break your proposed IF*
> syntax. So let's not go there.

NiCLOS is "Nickel-OS". If it makes you think of batteries
I hope you at least get a charge out of it. ;)
The persistent object db is "NiCORE", which refers
to a raw Nickel mineral deposit.
I suppose NiCad would be a CAD program written for NiCLOS?

Note that a machine running NiCLOS isn't a Lisp Machine,
but a "Slot Machine" as NiCLOS objects have "slots",
and of particular note are "Nickel Slots", which is the cheapest
form of Gambling in Las Vegas.

Just my $0.05 ;)

kelly murray

Vassil Nikolov

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
In article <36F6CC00...@simplex.nl>,
Arthur Lemmens <lem...@simplex.nl> wrote:
(...)

> it's often better
> to use LOOP
(...)

> Right now, you may think that you just need to transform the elements
> of a list, and MAP may work just as well as LOOP. But in a later stage
> you may discover that you don't just want to transform the elements, you
> also want to count them. If you'd used LOOP from the beginning, you
> would
> just add an extra clause. But if you'd used MAP, you would have to wrap
> a
> LET around it and insert an INCF inside the LAMBDA.
(...)

I wish you'd given another example rather than MAP vs. LOOP.

Please do correct me if I am wrong, but last time I looked I could
not find a LOOP clause that could iterate across a _sequence_
(regardless if it was a list or vector). MAP can, and wins for me.

Vassil Nikolov <vnik...@poboxes.com> www.poboxes.com/vnikolov
(You may want to cc your posting to me if I _have_ to see it.)
LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)

-----------== Posted via Deja News, The Discussion Network ==----------

Vassil Nikolov

unread,
Mar 23, 1999, 3:00:00 AM3/23/99
to
> Excuse me, but *gag*

gag, vt (...) (fig) deprive (sb) of free speech (...)

Now let's see, which is the number of the relevant Amendment...

If you read my previous post, you'd see that I already wrote that
I'd rather have forms surrounded by (). So I should be glad you
support my opinion.

You responded to what was essentially an endnote (whose last phrase
was intended to sound self-ironic; I guess my tactic of using classical
punctuation devices rather than smileys doesn't work very well).

But if you say I was serious in suggesting {}, and especially the
trailing asterisk, so be it. Not that I have managed to fool anyone
in wasting their time implementing that syntax.

> Seriously, a great thing about lisp is that there is only one *delimiting*
> syntax - (). (Yes, there are other parts of the syntax, such as , and ' and
> `, but they are not syntactic delimiters.) Now, if you throw in a {} pair
> as well, it will take that much more effort to read lisp syntax. Suddenly
> you would have to pay attention to the particular delimiter, and not just
> the fact that it is a delimiter. It is an additional load I don't really

> care to have. At first I didn't like the fact that ' and ` are so similar
> either, but the effect they have is similar enough that it does not bother
> me that much. But ( and { appear to have distinct enough semantic
> properties that I may never ease into this syntax. Add to that the fact
> that in some fonts on some displays { and ( don't look all that
> different...
>
> Finally, as to the {}* syntax, I would much rather have something like
> {* ... }. That way at least you know up front that it is a loop, rather
> than having to wait upto the end to find out that it is a loop and then
> having to reparse the code. Much more in keeping with the usual lisp
> syntax, IMHO.
>
> Sunil
>

Vassil Nikolov <vnik...@poboxes.com> www.poboxes.com/vnikolov

Vassil Nikolov

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
In article <yq7zp54...@qobi.nj.nec.com>,

That was not such ancient history. My first Lisp (Integral Quality Lisp)
had this `feature.' I am glad I happened to not pick it up (just happened,
pure luck, unless it was intuition of course).

I had no idea this came from InterLisp, though.

Vassil Nikolov

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
In article <87soawd...@2xtreme.net>,

Oh, IF, I say, you come upon this verse
WHEN I perhaps compounded am with clay,
DO not so much my poor name rehearse
but LET your love even with my life decay.

Lest THE wise world should look into your moan,
AND mock you with me after I am gone.

(Just an association. This is #71 I think.)

Christopher R. Barry

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
Vassil Nikolov <vnik...@poboxes.com> writes:

> Please do correct me if I am wrong, but last time I looked I could
> not find a LOOP clause that could iterate across a _sequence_

^^^^^^


> (regardless if it was a list or vector). MAP can, and wins for me.

* (loop for char across "foo" do (print char))
#\f
#\o
#\o
NIL
* (loop for element across #(1 2 3) do (print element))
1
2
3
NIL

Christopher

Sunil Mishra

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
Vassil Nikolov <vnik...@poboxes.com> writes:

> You responded to what was essentially an endnote (whose last phrase
> was intended to sound self-ironic; I guess my tactic of using classical
> punctuation devices rather than smileys doesn't work very well).
>
> But if you say I was serious in suggesting {}, and especially the
> trailing asterisk, so be it. Not that I have managed to fool anyone
> in wasting their time implementing that syntax.

Hmmm, well, I suppose I ought to learn to pay a little more attention to
history... :-)

Sunil

Gareth McCaughan

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
Christopher Barry wrote:

> Vassil Nikolov <vnik...@poboxes.com> writes:
>
>> Please do correct me if I am wrong, but last time I looked I could
>> not find a LOOP clause that could iterate across a _sequence_
> ^^^^^^
>> (regardless if it was a list or vector). MAP can, and wins for me.

^^^^


> * (loop for char across "foo" do (print char))
> #\f
> #\o
> #\o
> NIL
> * (loop for element across #(1 2 3) do (print element))
> 1
> 2
> 3
> NIL

| * (loop for element across '(1 2 3) do (print element))
| [...]
| Type-error in KERNEL::OBJECT-NOT-TYPE-ERROR-HANDLER:
| (1 2 3) is not of type ARRAY

--
Gareth McCaughan Dept. of Pure Mathematics & Mathematical Statistics,
gj...@dpmms.cam.ac.uk Cambridge University, England.

Arthur Lemmens

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to

> Vassil Nikolov <vnik...@poboxes.com> writes:
> Please do correct me if I am wrong, but last time I looked I could
> not find a LOOP clause that could iterate across a _sequence_
> (regardless if it was a list or vector). MAP can, and wins for me.

"Christopher R. Barry" replies:


> * (loop for char across "foo" do (print char))
> #\f
> #\o
> #\o
> NIL
> * (loop for element across #(1 2 3) do (print element))

I think Vassil means something else.
With MAP, you can write functions like:

(defun map-types (sequence)
(map (type-of sequence) #'type-of sequence))

that work for both lists and vectors:

(map-types '(a 1 #\x)) -> (SYMBOL BIT STANDARD-CHAR)
(map-types #(a 1 #\x)) -> #(SYMBOL BIT STANDARD-CHAR)

You can't use LOOP in cases like this, because there's no clause
that will work for *both* vectors and lists.
I agree with Vassil that this is a problem with LOOP, although I don't
think that MAP wins when you want to do more than just map.

But I do sorely miss a facility that allows me to loop efficiently
over both vectors and lists.

Here's a real-life example, taken from some quick-and-dirty code
for generating Javascript:

(defun array-declaration-and-initialization (name list &key (key
#'identity))
;; DO: I'd rather accept a sequence instead of a list, but then
;; I'd have to duplicate the loop-code.
(array-declaration name)
(loop for entry in list
and index from 0
collect (array-elt-assignment name index (funcall key entry))))

When people complain about the lack of iterators in Common Lisp,
I always assume they have examples like this in mind.

Arthur


st.a...@ncsu.edu

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
Arthur Lemmens <lem...@simplex.nl> writes:
> With MAP, you can write functions like:
>
> (defun map-types (sequence)
> (map (type-of sequence) #'type-of sequence))
>
> that work for both lists and vectors:
>
> (map-types '(a 1 #\x)) -> (SYMBOL BIT STANDARD-CHAR)
> (map-types #(a 1 #\x)) -> #(SYMBOL BIT STANDARD-CHAR)

This is a nice solution, but in Allegro you get this response to the
first form:

Error: CONS is an invalid output type specifier.

. . . because of course '(a 1 #\x) is a cons. I've ended up defining
a trivial type-of-sequence function as a workaround. Is there a
better way?

Rob St. Amant

Christopher R. Barry

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
Gareth McCaughan <gj...@dpmms.cam.ac.uk> writes:

> Christopher Barry wrote:
>
> > Vassil Nikolov <vnik...@poboxes.com> writes:
> >
> >> Please do correct me if I am wrong, but last time I looked I could
> >> not find a LOOP clause that could iterate across a _sequence_

> > ^^^^^^


> >> (regardless if it was a list or vector). MAP can, and wins for me.

> ^^^^


> > * (loop for char across "foo" do (print char))
> > #\f
> > #\o
> > #\o
> > NIL
> > * (loop for element across #(1 2 3) do (print element))

> > 1
> > 2
> > 3
> > NIL
>

> | * (loop for element across '(1 2 3) do (print element))
> | [...]
> | Type-error in KERNEL::OBJECT-NOT-TYPE-ERROR-HANDLER:
> | (1 2 3) is not of type ARRAY

I don't see the big deal with just saying

(loop for element in list do (stuff ...))

when iterating across a list and

(loop for element across vector do (stuff ...))

when doing a vector. Maybe this is part of why LOOP nearly always
results in tighter code than MAP and friends.... I never use MAP
functions nor APPLY or REDUCE and seldom use recursion, because I can
get the job done with less code (or at least clearer IMO) with LOOP
and also more efficiently.

Also, instead of putting a bunch of ugly DECLARE forms all over your
code, LOOP makes providing type information aesthetic.

* (loop for char of-type character across (the simple-string "abc")
do (write-char char))
abc
NIL

Christopher

Christopher R. Barry

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
Arthur Lemmens <lem...@simplex.nl> writes:

> I think Vassil means something else.

> With MAP, you can write functions like:
>
> (defun map-types (sequence)
> (map (type-of sequence) #'type-of sequence))
>
> that work for both lists and vectors:
>
> (map-types '(a 1 #\x)) -> (SYMBOL BIT STANDARD-CHAR)
> (map-types #(a 1 #\x)) -> #(SYMBOL BIT STANDARD-CHAR)
>

> You can't use LOOP in cases like this, because there's no clause
> that will work for *both* vectors and lists.
> I agree with Vassil that this is a problem with LOOP, although I don't
> think that MAP wins when you want to do more than just map.
>
> But I do sorely miss a facility that allows me to loop efficiently
> over both vectors and lists.
>
> Here's a real-life example, taken from some quick-and-dirty code
> for generating Javascript:
>
> (defun array-declaration-and-initialization (name list &key (key
> #'identity))
> ;; DO: I'd rather accept a sequence instead of a list, but then
> ;; I'd have to duplicate the loop-code.
> (array-declaration name)
> (loop for entry in list
> and index from 0
> collect (array-elt-assignment name index (funcall key entry))))
>
> When people complain about the lack of iterators in Common Lisp,
> I always assume they have examples like this in mind.

You say you'd rather have a SEQUENCE, but why? Any SEQUENCE is either
a LIST or a VECTOR, so you can cover 100% of the SEQUENCE terain by
only accepting both if it's really important. Just write a method. If
it did accept a SEQUENCE than there would still likely be some
additional checking/dispatching behind the scenes by the
implementation anyways, so don't feel like you're incuring the
ultimate performance penaltly by doing this.

Geez, Java must be _extremely_ painful for you since all anyone does
in that language is write 20 different methods that do the exact same
thing but must be coded seperately because of the types they
accept. So you're essentially simulating a weak-typed language and
doing all the book-keeping yourself.

What would have really been nice is if from CLTL2 we had


26.4. User Extensibility

There is currently no specified portable method for users to add
extensions to the Loop Facility. The names defloop and
define-loop-method have been suggested as candidates for such a
method.

Christopher

Raymond Toy

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
>>>>> "Christopher" == Christopher R Barry <cba...@2xtreme.net> writes:

Christopher> when doing a vector. Maybe this is part of why LOOP nearly always
Christopher> results in tighter code than MAP and friends.... I never use MAP
Christopher> functions nor APPLY or REDUCE and seldom use recursion, because I can
Christopher> get the job done with less code (or at least clearer IMO) with LOOP
Christopher> and also more efficiently.

In Norvig's book on Paradigms of AI, he gives an example of using map
(or reduce, or something like that), and shows that CMUCL actually
converts it to an equivalent do loop, that probably would be as
efficient as your loop.

I guess this means you need a smarter compiler[1].

Christopher> Also, instead of putting a bunch of ugly DECLARE forms all over your
Christopher> code, LOOP makes providing type information aesthetic.

Christopher> * (loop for char of-type character across (the simple-string "abc")
Christopher> do (write-char char))

But a really smart compiler should be able to figure out the type of
char itself from the simple-string. I'm not aware of any such
compiler, though (but haven't looked either).

Ray

Footnotes:
[1] I think CMUCL had a start on doing even more code transformations
of this sort, but I don't think they were ever finished. That would
have been really cool.


Arthur Lemmens

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to

Me:

> But I do sorely miss a facility that allows me to loop efficiently
> over both vectors and lists.
>
> Here's a real-life example, taken from some quick-and-dirty code
> for generating Javascript:
>
> (defun array-declaration-and-initialization (name list &key (key
> #'identity))
> ;; DO: I'd rather accept a sequence instead of a list, but then
> ;; I'd have to duplicate the loop-code.
> (array-declaration name)
> (loop for entry in list
> and index from 0
> collect (array-elt-assignment name index (funcall key entry))))

"Christopher R. Barry":

> You say you'd rather have a SEQUENCE, but why?

Because I don't want to have to decide yet.
This function makes as much sense for a list as for a vector.

Here's another example, slightly more complicated, from my UTILS file:

CL-USER 10 >
(defun empty-sequence-p (x)
(or (null x) (and (not (consp x)) (zerop (length x)))))
EMPTY-SEQUENCE-P

CL-USER 11 >
(defun singleton-p (x)
(or (and (consp x) (null (cdr x)))
(= (length x) 1)))
SINGLETON-P

CL-USER 20 >
(defun delimit (seq delimiter)
(if (or (empty-sequence-p seq)
(singleton-p seq))
seq
(let ((result (make-sequence (type-of seq)
(- (* 2 (length seq)) 1)
:initial-element delimiter)))
(if (consp seq)
;; THESE ARE THE SAME LOOPS, ONLY THE ITERATORS ARE OF A DIFFERENT TYPE.
;; CAN'T WE UNIFY THIS SOME WAY??
(loop for source in seq
and dest on result by #'cddr
do (setf (car dest) source))
(loop for i from 0 to (- (length seq) 1)
and j from 0 by 2
do (setf (elt result j) (elt seq i))))
result)))

DELIMIT

CL-USER 21 > (delimit "abc" #\space)
"a b c"

CL-USER 22 > (delimit '("a=1" "b=2" "c=3") "; ")
("a=1" "; " "b=2" "; " "c=3")

CL-USER 23 > (delimit '(x y z) '+)
(X + Y + Z)


> Any SEQUENCE is either a LIST or a VECTOR, so you can cover 100% of
> the SEQUENCE terain by only accepting both if it's really important.
> Just write a method.

Sure, that's just a different way to dispatch.
My point is: sometimes I don't want to do the dispatch in my own code.
I would like a LOOP clause to take care of this for me, just like the
built-in sequence functions do. I'm willing to accept a small
efficiency loss in return for the generality this could buy me.



> What would have really been nice is if from CLTL2 we had
>
> 26.4. User Extensibility
>
> There is currently no specified portable method for users to add
> extensions to the Loop Facility. The names defloop and
> define-loop-method have been suggested as candidates for such a
> method.

Yes.
I think it wouldn't be extremely difficult to come up with a way to
implement what I'm suggesting above, but at the moment it's impossible
to do this portably. (Except by rewriting the whole LOOP macro from
scratch.)

Arthur


Arthur Lemmens

unread,
Mar 24, 1999, 3:00:00 AM3/24/99
to
I wrote:
> With MAP, you can write functions like:
>
> (defun map-types (sequence)
> (map (type-of sequence) #'type-of sequence))
>
> that work for both lists and vectors:
>
> (map-types '(a 1 #\x)) -> (SYMBOL BIT STANDARD-CHAR)
> (map-types #(a 1 #\x)) -> #(SYMBOL BIT STANDARD-CHAR)

Rob St. Amant replies:


> This is a nice solution, but in Allegro you get this response to the
> first form:
>
> Error: CONS is an invalid output type specifier.

That's weird.
The Hyperspec says:
1. The class precedence list for CONS is: CONS LIST SEQUENCE T.
2. About the first argument for MAP, the result type:
"If the result type is a subtype of list, the result will be a list.'

So I would think that this is a bug in Allegro.
If I understand the Hyperspec correctly, CONS is a *valid* result type
specifier for MAP.

On Windows, Harlequin's Lispworks 4.1 handles this the way
I'd expect. Corman Lisp 1.1 gives an error.

Arthur

Vassil Nikolov

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to
In article <87lngme...@2xtreme.net>,

cba...@2xtreme.net (Christopher R. Barry) wrote:
> I don't see the big deal with just saying
>
> (loop for element in list do (stuff ...))
>
> when iterating across a list and
>
> (loop for element across vector do (stuff ...))
>
> when doing a vector. Maybe this is part of why LOOP nearly always
> results in tighter code than MAP and friends.... I never use MAP
> functions nor APPLY or REDUCE and seldom use recursion, because I can
> get the job done with less code (or at least clearer IMO) with LOOP
> and also more efficiently.

Let me explain my point.

It often happens that I need a sequence in my data, and from the
point of view of the _problem_ all that it matters is that it is
a sequence. In such cases, I want to make my program independent
of the particular choice of sequence (list or vector) as much as
possible, but on the other hand I often do not want to go to the
trouble of writing all proper abstractions. In such cases, I
find MAP very useful.

In other words, if I have decided for sure that it is a list or
a vector, there is indeed no big deal in using the corresponding
LOOP clauses (above). But often I don't want to be bound by such
a decision at program writing time, at least during development.
If it turns out to be important for speed or whatever, later, I
can set the relevant places to use the most specific iteration
construct.

By the way, since REDUCE was mentioned, let me say that it does
help me write simpler code. For example, consider turning
a bit vector into an integer (this has happened to me, and also
appeared not very long ago in this group):

(reduce #'(lambda (k l) (+ (* 2 k) l)) #*011010101)

How does one do this with a LOOP _one-liner_? If one uses LOOP
or some such, one has to introduce the accumulator explicitly
and explicitly specify it being returned from the loop.

(Even if one cannot assume that the bit vector has at least 2
elements, keyword arguments to REDUCE can help to avoid writing
a lot of additional code.)

Pierre R. Mai

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to
cba...@2xtreme.net (Christopher R. Barry) writes:

> You say you'd rather have a SEQUENCE, but why? Any SEQUENCE is either


> a LIST or a VECTOR, so you can cover 100% of the SEQUENCE terain by

> only accepting both if it's really important. Just write a method. If

But this is of course completely the wrong way around, isn't it? Time
and time again it has been found that the correct way of doing things
is to keep them general most of the time, and only restrict this
generality when there are sound reasons, like e.g. proven performance
problems. Keeping in line with your reasoning, Common Lisp is all
wrong and Java&Co. are right, since they carry this out in perfect,
agonizing detail: Keep things special, and only ever start going
general if it's REALLY IMPORTANT. Which is why you mostly never get
general solutions, but much duplication via copy-paste programming.
At least C++ programmers have seen the problem of this, and invented
the automatic copy-paste-mechanism, a.k.a. the template mechanism :->

> Geez, Java must be _extremely_ painful for you since all anyone does

Well, Java IS quite painful. See the various efforts of grafting
templates onto Java...

> What would have really been nice is if from CLTL2 we had
>
>
> 26.4. User Extensibility
>
> There is currently no specified portable method for users to add
> extensions to the Loop Facility. The names defloop and
> define-loop-method have been suggested as candidates for such a
> method.

Yes, user extensibility for loop is quite nice. OTOH don't most
implementations have this anyways? Every implementation that use a
variant of the original MIT loop code should IMHO have this via
add-loop-path&co. IIRC, Allegro 5.0 has this, and CMUCL has it too,
and I'd be surprised if there weren't more implementations. Given
that there is general agreement that the ANSI spec doesn't properly
specify several aspects of loop clause interactions, it seems to me,
many implementors tried to get out of this by basing their loop
implementations on the MIT code, so they were compatible. CMUCL
e.g. had it's own implementation and then changed over to the MIT
implementation because of that.

But this area would be nice to go over in any upcoming revision of the
standard... Just look at what Harlequin's Common SQL does with loop
for iterating over SQL query results. This kind of thing crop's up
often, and it's really nice to be able to do this...

Regs, Pierre.

--
Pierre Mai <pm...@acm.org> http://home.pages.de/~trillian/
"One smaller motivation which, in part, stems from altruism is Microsoft-
bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]

Arthur Lemmens

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to

"Pierre R. Mai" wrote:
> Yes, user extensibility for loop is quite nice. OTOH don't most
> implementations have this anyways?

For Lispworks, I haven't found any documentation about extending LOOP.

> Given that there is general agreement that the ANSI spec doesn't
> properly specify several aspects of loop clause interactions,

Do you have any references for this 'general agreement'?
The only thing I'm aware of is a remark by Paul Graham in
"ANSI Common Lisp".

Arthur


Sunil Mishra

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to
Vassil Nikolov <vnik...@poboxes.com> writes:


> By the way, since REDUCE was mentioned, let me say that it does
> help me write simpler code. For example, consider turning
> a bit vector into an integer (this has happened to me, and also
> appeared not very long ago in this group):
>
> (reduce #'(lambda (k l) (+ (* 2 k) l)) #*011010101)
>
> How does one do this with a LOOP _one-liner_? If one uses LOOP
> or some such, one has to introduce the accumulator explicitly
> and explicitly specify it being returned from the loop.

That is if you attempt a literal translation. This is probably the clearest
version I can produce using loop:

(loop with v = #*011010101
for exp = 1 then (* 2 exp)
and index from (1- (length v)) downto 0
sum (* exp (aref v index)))

Yes, it's longer, by about a line. But then I had to stare at your code for
a couple of minutes (may simply be "early" morning sluggishness (my days
start late)) before I could figure out what it was doing. I find the loop
version is just a little more explicit, which makes the extra line or so of
code worth it.

I tend to choose between loop and map by first deciding which makes it more
explicit precisely what I am trying to do. Sometimes it's loop, sometimes
it's map (or reduce, or some other function applier). Sometimes it's a
matter of taste, sometimes the time of day. I find it fascinating that this
minor an issue can generate so much discussion :-)

Sunil

Dave Pearson

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to
On 25 Mar 1999 18:32:23 +0200, Sunil Mishra <smi...@cleon.cc.gatech.edu> wrote:
> Vassil Nikolov <vnik...@poboxes.com> writes:
>
> > (reduce #'(lambda (k l) (+ (* 2 k) l)) #*011010101)

As someone who dabbles in lisp the above line did make my morning, one of
those lines of code that sends you off thinking in a new direction and, at
the same time, seems really obvious once you've read it.

> That is if you attempt a literal translation. This is probably the clearest
> version I can produce using loop:
>
> (loop with v = #*011010101
> for exp = 1 then (* 2 exp)
> and index from (1- (length v)) downto 0
> sum (* exp (aref v index)))

This was my loop attempt when I read the above this morning:

(loop for bit across (reverse #*011010101)
and exp = 1 then (ash exp 1)
sum (* bit exp))

Not that this lisp novice is suggesting this is better or worse or anything,
but given:

> I find it fascinating that this minor an issue can generate so much
> discussion :-)

I thought it only fair to let it be known that at least one lurker gets a
kick out of learning from such posts.

--
Take a look in Hagbard's World: | w3ng - The WWW Norton Guide reader.
http://www.acemake.com/hagbard/ | eg - Norton Guide reader for Linux.
http://www.hagbard.demon.co.uk/ | weg - Norton Guide reader for Windows.
Free software, including........| dgscan - DGROUP scanner for Clipper.


Mike McDonald

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to
In article <efypv5x...@cleon.cc.gatech.edu>,

Sunil Mishra <smi...@cleon.cc.gatech.edu> writes:
> Vassil Nikolov <vnik...@poboxes.com> writes:
>
>
>> By the way, since REDUCE was mentioned, let me say that it does
>> help me write simpler code. For example, consider turning
>> a bit vector into an integer (this has happened to me, and also
>> appeared not very long ago in this group):
>>
>> (reduce #'(lambda (k l) (+ (* 2 k) l)) #*011010101)
>>
>> How does one do this with a LOOP _one-liner_? If one uses LOOP
>> or some such, one has to introduce the accumulator explicitly
>> and explicitly specify it being returned from the loop.
>
> That is if you attempt a literal translation. This is probably the clearest
> version I can produce using loop:
>
> (loop with v = #*011010101
> for exp = 1 then (* 2 exp)
> and index from (1- (length v)) downto 0
> sum (* exp (aref v index)))
>

That's clearer? How about the good old fashion way:

(loop with num = 0
for bit across #*011010101
do (setf num (+ (* 2 num) bit))
finally (return num))

or how about:

(loop for bit across #*011010101
for num = bit then (+ (* 2 num) bit)
finally (return num))

Mike McDonald
mik...@mikemac.com

Sunil Mishra

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to
Vassil Nikolov <vnik...@poboxes.com> writes:

> Well, I am going to stop here (not that I have nothing more to say).
> And I am very pleased that for yet another time Parkinson's laws have
> been in force. He describes in his book an imaginary meeting where
> a 10 million pound investment decision passes after fleeting discussion
> but a 500 pound cost is discussed for a long time---but please read the
> book if you haven't, there are very interesting conclusions there.

I've never heard of the author. Can you tell me more? (Publisher, year,
ISBN, or some such?)

Sunil

Vassil Nikolov

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
In article <7dcd9c$gmb$1...@nnrp1.dejanews.com>,
Vassil Nikolov <vnik...@poboxes.com> wrote:
(...)

> By the way, since REDUCE was mentioned, let me say that it does
> help me write simpler code. For example, consider turning
> a bit vector into an integer (this has happened to me, and also
> appeared not very long ago in this group):
>
> (reduce #'(lambda (k l) (+ (* 2 k) l)) #*011010101)
>
> How does one do this with a LOOP _one-liner_? If one uses LOOP
> or some such, one has to introduce the accumulator explicitly
> and explicitly specify it being returned from the loop.

I made an overstatement. It has been pointed out to me that the above
_can_ in fact be done with a LOOP one-liner using SUM, a capability
that I had plainly forgotten, where LOOP provides an accumulator
implicitly.

(I could, but I didn't, say `bit sequence' or pick up a little
more complex example, something like xoring all the bits perhaps.)

Vassil Nikolov

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
In article <efypv5x...@cleon.cc.gatech.edu>,
Sunil Mishra <smi...@cleon.cc.gatech.edu> wrote:
(...)

> I tend to choose between loop and map by first deciding which makes it more
> explicit precisely what I am trying to do. Sometimes it's loop, sometimes
> it's map (or reduce, or some other function applier). Sometimes it's a

Indeed, this decision must come first.

> matter of taste, sometimes the time of day. I find it fascinating that this


> minor an issue can generate so much discussion :-)

:-)

Well, I am going to stop here (not that I have nothing more to say).
And I am very pleased that for yet another time Parkinson's laws have
been in force. He describes in his book an imaginary meeting where
a 10 million pound investment decision passes after fleeting discussion
but a 500 pound cost is discussed for a long time---but please read the
book if you haven't, there are very interesting conclusions there.

Vassil Nikolov <vnik...@poboxes.com> www.poboxes.com/vnikolov

Vassil Nikolov

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
In article <7de0fa$537$1...@spitting-spider.aracnet.com>,
> Sunil Mishra <smi...@cleon.cc.gatech.edu> writes:
> > Vassil Nikolov <vnik...@poboxes.com> writes:
> >
> >
> >> By the way, since REDUCE was mentioned, let me say that it does
> >> help me write simpler code. For example, consider turning
> >> a bit vector into an integer (this has happened to me, and also
> >> appeared not very long ago in this group):
> >>
> >> (reduce #'(lambda (k l) (+ (* 2 k) l)) #*011010101)
> >>
> >> How does one do this with a LOOP _one-liner_? If one uses LOOP
> >> or some such, one has to introduce the accumulator explicitly
> >> and explicitly specify it being returned from the loop.
> >
> > That is if you attempt a literal translation. This is probably the clearest
> > version I can produce using loop:
> >
> > (loop with v = #*011010101
> > for exp = 1 then (* 2 exp)
> > and index from (1- (length v)) downto 0
> > sum (* exp (aref v index)))
> >
>
> That's clearer? How about the good old fashion way:
>
> (loop with num = 0
> for bit across #*011010101
> do (setf num (+ (* 2 num) bit))
> finally (return num))
>
> or how about:
>
> (loop for bit across #*011010101
> for num = bit then (+ (* 2 num) bit)
> finally (return num))

I just said I'd stop... Every decision is the last-but-one.

My point was: no explicit accumulator. And NUM is one. With
LOOP, I want SUM here, as in the implementations in other
postings.

Fernando D. Mato Mira

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to

Vassil Nikolov wrote:

> That was not such ancient history. My first Lisp (Integral Quality Lisp)
> had this `feature.'

Gee. As I could not find a Lisp for my Timex Sinclair, I had to wait until
the first day I got an account at the to the university to log on VAX 780 Lisp.
I tried a couple of forms, but it was just too slow. So my first real Lisp
experiences
came with IQLisp too a year later (well, if you don't count some Pascal work we had

during the first semester where I went head-on with dynamic memory management,
calling all list ops CAR, CDR and so on ;-) )

The first comp mag I ever bought was Computer Language, when I was 15,
and it had a little article on Lisp (had I seen it before?). Anyway I remember
I was doomed that precise day ;-)

--
Fernando D. Mato Mira
Real-Time SW Eng & Networking
Advanced Systems Engineering Division
CSEM
Jaquet-Droz 1 email: matomira AT acm DOT org
CH-2007 Neuchatel tel: +41 (32) 720-5157
Switzerland FAX: +41 (32) 720-5720

www.csem.ch www.vrai.com ligwww.epfl.ch/matomira.html

Fernando D. Mato Mira

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to

Dorai Sitaram wrote:

> being used in _some_ Schemes for "mere" syntax
> highlighting, they can't be exploited for introducing
> meaningful new syntax. (Cf. letter case.)

Yes they can. Just boycott those brain damaged
Scheme implementations.

Paolo Amoroso

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
On 25 Mar 1999 21:24:33 -0500, Sunil Mishra
<smi...@peachtree.cc.gatech.edu> wrote:

> Vassil Nikolov <vnik...@poboxes.com> writes:
[...]


> > And I am very pleased that for yet another time Parkinson's laws have
> > been in force. He describes in his book an imaginary meeting where
> > a 10 million pound investment decision passes after fleeting discussion
> > but a 500 pound cost is discussed for a long time---but please read the

Parkinson's Law of Triviality: "The time spent on any item of the agenda
will be in inverse proportion to the sum involved".


> I've never heard of the author. Can you tell me more? (Publisher, year,
> ISBN, or some such?)

"Parkinson: The Law, Complete - The whole truth about the madness
of modern management from the great Lawgiver"
C. Northcote Parkinson
Ballantine Books, 1990
212 pages; price around 5$
ISBN 0-345-30064-5


Have fun


Paolo
--
Paolo Amoroso <amo...@mclink.it>

Vassil Nikolov

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
In article <efyemmd...@peachtree.cc.gatech.edu>,

Sunil Mishra <smi...@peachtree.cc.gatech.edu> wrote:
> Vassil Nikolov <vnik...@poboxes.com> writes:
>
> > Well, I am going to stop here (not that I have nothing more to say).
> > And I am very pleased that for yet another time Parkinson's laws have
> > been in force. He describes in his book an imaginary meeting where
> > a 10 million pound investment decision passes after fleeting discussion
> > but a 500 pound cost is discussed for a long time---but please read the
> > book if you haven't, there are very interesting conclusions there.
>
> I've never heard of the author. Can you tell me more? (Publisher, year,
> ISBN, or some such?)

He wrote quite a number of books. I have these references at hand:

C. Northcote Parkinson
Parkinson Law or The Pursuit of Progress
John Murray, ALbermale Street, London, 1957

C. Northcote Parkinson
In-Laws and Out-Laws
John Murray, ALbermale Street, London
Roturman, S. A., 1962

Sorry, I have no ISBN. I suppose they were published by US publishers
too.

Pierre R. Mai

unread,
Mar 29, 1999, 3:00:00 AM3/29/99
to
Arthur Lemmens <lem...@simplex.nl> writes:

> "Pierre R. Mai" wrote:
> > Yes, user extensibility for loop is quite nice. OTOH don't most
> > implementations have this anyways?
>
> For Lispworks, I haven't found any documentation about extending LOOP.

Hmmm, strange, but I dimly remember stumbling across some
documentation for Lispworks which dealt with LOOP extensions, but now
that I'm looking for it, I can't seem to find something, too. So
maybe I misremember...

> > Given that there is general agreement that the ANSI spec doesn't
> > properly specify several aspects of loop clause interactions,
>
> Do you have any references for this 'general agreement'?
> The only thing I'm aware of is a remark by Paul Graham in
> "ANSI Common Lisp".

There where previous discussions about this topic on comp.lang.lisp,
in which I think there were also references to texts on this topic.
Try a search via DejaNews, and I think you'll find something...

See also some of the older release notes of CMU CL, where you'll find
a number of comments which indicate similar concerns with the ANSI
spec, and more importantly with the MIT implementation (together with
the accompanying test-suite) becoming the de-facto standard...

Now this is only circumstancial evidence, and some readers of this
group might like to contradict me (especially e.g. Kent Pitman, who'll
probably have much more direct evidence and insight into these issues,
hint, hint <g>), since I'm neither an implementor, nor was I around at
the time...

Anyways, if there are ambiguities in the spec, they are not that
serious in day to day usage of loop, since they mostly involved
complex interplay between iteration clauses IIRC, which not only the
spec, but most programmers wouldn't be certain how to interpret, so
they should be avoided in production code anyways (a bit like this
sentence is much to long and complex, and should be broken down into
simpler and clearer sentences, which I'm quite to lazy to do this late
in the night...)

Kent M Pitman

unread,
Mar 29, 1999, 3:00:00 AM3/29/99
to
pm...@acm.org (Pierre R. Mai) writes:

> Anyways, if there are ambiguities in the spec [about LOOP],
> they are not that serious in day to day usage of loop, [...]

I recall there being some gaping hole in which we didn't specify whether
a loop binding was allowed to refer to itself. I don't recall if we
fixed that. A careful reading would probably say. There was originally
some intentional(!) fuzziness in which
(loop for x in x ...)
didn't work because it was permitted but not required to expand into
an outer let binding that bound x and then an inner one that did the
init of x, so that the x got evaluated in the conceptually wrong
environment. I remember wanting this cleaned up and people telling me
this was necessary for efficiency and me asking what the point of
efficiency was if you didn't know what the operator would do and ...
but I don't remember what the outcome was.

Other than that one item, I don't recall any ambiguities. Earlier loop
stuff (descended from lispm) had the weird property that differences
in order had odd effects .. e.g.,
(loop for x from 1 to 3 collect x)
and
(loop collecting x for x from 1 to 3)
didn't return the same thing. I think ANSI CL fixed this by insisting
that the binding clauses had to precede the collection clauses. (But
in the older reading, pre-CL, the collection happened before the end
test because the collection appeared before the binding..)

As far as I know, LOOP's principal "ambiguity problem" is the accidental
confusion with English that is both its strength and its weakness.

As to extending LOOP, that was in there originally and the committee
ended up removing it over petty politics, if I recall correctly. (I
might me misremembering, but the specific recollection I think I have
is one of people quibbling over whose extension language we'd
use--there were maybe more than one...) LOOP has been extensible ever
since I can remember seeing it (like all the way back to 1979 or 1980
or so). LOOP "paths", as they were called, were things lots of people
used to make and it was ridiculous that we didn't offer a way of
extending LOOP. I confess I didn't personally take my much interest
in LOOP either way until a few years ago because pre-CL loop was
underconstrained in ways that made me really hate it. I still don't
like the syntax hugely, but I have come to respect its ability to
allow me to articulate abstract concepts in a modular way that is
painful to write any other way, and largely I put up with it because
although I am quite comfortable writing DO, I often find the result
less perspicuous. Also, LOOP has the property that if you have to
change it, you don't have to reshape it as drastically as DO usually
makes you do. It's been mostly the getting rid of the ambiguous parts
of LOOP that have let me feel more comfortable with it. Maybe Barmar
or SMH remembers better...? I feel a bit uncertain about some of these
memories...

0 new messages