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

Anti-Loop

456 views
Skip to first unread message

WJ

unread,
Mar 7, 2012, 4:48:18 AM3/7/12
to

In PCL, there is a chapter promoting the use of the COBOL-like
LOOP. I think that the examples can be done more elegantly
without LOOP by using NewLisp.



The low, loopy way:

(loop for i upto 10 collect i)


The high way:

(sequence 0 10)





The low, loopy way:

(loop repeat 5
for x = 0 then y
for y = 1 then (+ x y)
collect y)
==> (1 2 4 8 16)


The high way:

(map (curry pow 2) (sequence 0 4))
==> (1 2 4 8 16)

Another way:

(series 1 2 5)
==> (1 2 4 8 16)




The low, loopy way:

(loop for (a nil) in '((1 2) (3 4) (5 6)) collect a)
==> (1 3 5)


The high way:

(map first '((1 2) (3 4) (5 6)))
==> (1 3 5)





The low, loopy way:

(loop for (a b) in '((1 2) (3 4) (5 6))
do (format t "a: ~a; b: ~a~%" a b))

==>
a: 1; b: 2
a: 3; b: 4
a: 5; b: 6


The high way:

(dolist (x '((1 2) (3 4) (5 6)))
(println (format "a: %d; b: %d" x)))

==>
a: 1; b: 2
a: 3; b: 4
a: 5; b: 6







The low, loopy way:

(loop for (item . rest) on '(0 1 2 3 4 5 6 7 8)
do (format t "~a" item)
when rest do (format t ", "))

==>
0, 1, 2, 3, 4, 5, 6, 7, 8


The high way:

(print (join (map string (sequence 0 8)) ", "))

==>
0, 1, 2, 3, 4, 5, 6, 7, 8




The low, loopy way:

(defparameter *random* (loop repeat 100 collect (random 10000)))

(loop for i in *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))

==>
(47 9964 543718 46 54)


The high way:

(setq *random* (rand 10000 100))

(append
(map (fn (f) (apply f *random*)) (list min max +))
(map (fn (f) (length (filter f *random*))) (list even? odd?)))

==>
(87 9996 522987 49 51)



Here are the definitions of odd? and even?:

(define (odd? n) (= 1 (% n 2)))
(define (even? n) (not (odd? n)))

Juanjo Garcia

unread,
Mar 7, 2012, 5:16:51 AM3/7/12
to
Old flame war about the loop macro appeared again in a recent thread.
There, I argued that one (for me, main) advantage of loop is to easy
re-reading of code, thereby favoring code reuse.

Frequently, the extra intellectual effort required to understand
alternatives (map, do, etc.) causes the brain to get a final triumph
sensation that can be misinterpreted as caused by the code being more
elegant.
(Another case of "worse is better" scenario.)

Perhaps "elegant" should be applied exclusively to algorithms, not
code.
When the underlying algorithm is the same, differing codes
can hardly be called more or less elegant,
only more or less obfuscated.

loop is against code obfuscation.

Alex Mizrahi

unread,
Mar 7, 2012, 6:50:55 AM3/7/12
to
> In PCL, there is a chapter promoting the use of the COBOL-like
> LOOP. I think that the examples can be done more elegantly
> without LOOP by using NewLisp.

Your problem is us-vs-them mentality. Sane people do not care whether
something is noble or "low", they care whether something is readable and
efficient. Terseness might help with readability in some cases, and
might work against this in other.

Elegance is a synthetic quality which includes readability, efficiency,
terseness and cleverness. It is highly subjective, of course.

I strongly recommend you reading first chapters of _Patterns of
Software_ by Richard P. Gabriel. (One about abstractions is most
important, but rest will help you to understand context.) It cleverly
describes what shit is actually important and which isn't. Perhaps it
will help you.

You do valuable job showing pieces of code with different approaches and
in different languages, but you sometimes get too bitter and combative.
If you cut that maybe you'll get more respect.

> The low, loopy way:
> (loop for i upto 10 collect i)
> The high way:
> (sequence 0 10)

I agree it is a useful shortcut if you do that a lot. Typically it is
called iota. It is included in many CL libraries, for example, SAPACLisp:

$ (sapa:iota 0 10 :type 'list)
(0 1 2 3 4 5 6 7 8 9 10)

There is nothing bad about LOOP here, however, because it is barely more
verbose, is very easy to understand and remember, and doesn't require
you to implement and memorize a function for a very specific task.

Normally you write it like this: (loop for i from 1 to 10 collect i)
It is fairly obvious that numbers 1 to 10 will be included.
However, what would (sequence 0 10) do? Does it return 10 elements 0..9
or 11 elements 0..10? It isn't obvious until you read documentation, And
reading documentation for a myriad of small functions is a bitch.

> The low, loopy way:
> (loop repeat 5
> for x = 0 then y
> for y = 1 then (+ x y)
> collect y)
> ==> (1 2 4 8 16)
> The high way:
>
> (map (curry pow 2) (sequence 0 4))
> ==> (1 2 4 8 16)

You're comparing low-level, optimized LOOP to a non-optimized HoF
version. It would be more correct to compare your code with this:

(loop for i from 0 to 4
collect (expt 2 i))

Now it is barely more verbose and is easier to read and understand.

And again, there is nothing newLISP specific here. CL library Alexandria
provides many useful, general-purpose utilities, particularly, curry and
iota. So:

$ (mapcar (curry #'expt 2) (iota 5))
(1 2 4 8 16)

> Another way:
> (series 1 2 5)
> ==> (1 2 4 8 16)

You can always write very short code with specialized functions.

> The low, loopy way:
> (loop for (a nil) in '((1 2) (3 4) (5 6)) collect a)
> ==> (1 3 5)
> The high way:
> (map first '((1 2) (3 4) (5 6)))
> ==> (1 3 5)

There is absolutely no need in LOOP here as it is a very simple map:

(mapcar #'first '((1 2) (3 4) (5 6)))

But if one wishes to use LOOP, it would be better to write

(loop for e in '((1 2) (3 4) (5 6)) collect (first e))

You do not understand purpose of LOOP. It's not supposed to replace
simple map. It's for cases of iteration where map isn't adequate or is
overly verbose or ugly.

> (loop for (a b) in '((1 2) (3 4) (5 6))
> do (format t "a: ~a; b: ~a~%" a b))
> The high way:
> (dolist (x '((1 2) (3 4) (5 6)))
> (println (format "a: %d; b: %d" x)))

I fail to understand your logic here. It looks like format uses some
destructuring, but why is it more straightforward to destructure with
format than with loop?

Note that one could easily write

(format t "a: ~a; b: ~a~%" b a)

I.e. change output without changing input. Output IS NOT SUPPOSED to
match input.

But when destructuring is bundled with FORMAT, you cannot do that. THIS
IS WHY it is bad to have a bunch of highly specialized functions instead
of an expressive language.

So I think LOOP is more elegant here.

> The low, loopy way:
> (loop for (item . rest) on '(0 1 2 3 4 5 6 7 8)
> do (format t "~a" item)
> when rest do (format t ", "))
> The high way:
> (print (join (map string (sequence 0 8)) ", "))

LOOP is not optimized to handle this specialized case, but it works here
too. Actually there is a shorter way to do this:

(loop for (item . rest) on '(0 1 2 3 4 5 6 7 8)
do (format t "~a~a" item (if rest ", " "")))

But, of course, when you need output you want FORMAT sublanguage rather
than a LOOP:

$ (format nil "~{~a~^, ~}" '(0 1 2 3 4 5 6 7 8))
"0, 1, 2, 3, 4, 5, 6, 7, 8"

This format string is fairly ugly, but I guess you would like it because
it is specialized for a particular task.

> The low, loopy way:
> (defparameter *random* (loop repeat 100 collect (random 10000)))
> (loop for i in *random*
> counting (evenp i) into evens
> counting (oddp i) into odds
> summing i into total
> maximizing i into max
> minimizing i into min
> finally (return (list min max total evens odds)))
> ==>
> (47 9964 543718 46 54)
> The high way:
> (setq *random* (rand 10000 100))
>
> (append
> (map (fn (f) (apply f *random*)) (list min max +))
> (map (fn (f) (length (filter f *random*))) (list even? odd?)))
>
> ==>
> (87 9996 522987 49 51)

In case with LOOP you don't need to collect stuff into a list, you can
process items on fly, so it can be much more efficient with long lists.
Also it gives you named variables, so you can output things like
average, std. deviation, difference between min and max and so on.
So it isn't a fair comparison. But I agree that it sucks to use LOOP
each time you need some statistics.

So my conclusion is that you've cherry-picked examples where LOOP is
marginally worse than your "high" method. But if you consider similar,
but different tasks it won't be as clear.

Also, you're not good with LOOP and you don't know well when to use it.

Also, you're trying to frame this as CL vs newLISP, but CL can do all
this stuff if you use some library.

It is true that CL's standard library is less than ideal: it includes
weird functions nobody uses, but misses really nice-to-have ones.

But this is fixed with third-party libraries. So I don't see it as a
serious topic in language comparison.

However, LOOP a provides reasonable answer for a lot of small tasks. Not
always shortest and best, but at least easily readable. So take it for
what it is: a catch-all for small functions which didn't make it to
standard.

Tamas Papp

unread,
Mar 7, 2012, 7:26:46 AM3/7/12
to
On Wed, 07 Mar 2012 13:50:55 +0200, Alex Mizrahi wrote:

> It is true that CL's standard library is less than ideal: it includes
> weird functions nobody uses, but misses really nice-to-have ones.
>
> But this is fixed with third-party libraries. So I don't see it as a
> serious topic in language comparison.
>
> However, LOOP a provides reasonable answer for a lot of small tasks. Not
> always shortest and best, but at least easily readable. So take it for
> what it is: a catch-all for small functions which didn't make it to
> standard.

I was very skeptical of LOOP when I started using CL, but I have
realized its usefulness for the small problems you describe above.

But the more I use LOOP, the more I long for a replacement,
specifically one that is

(1) extensible, preferably using itself as a DSL,

(2) handles destructuring, via an extensible destructuring library
(like let+ or bind),

(3) handles collection in an extensible manner.

(4) doesn't use a code walker,

(5) compiles into fairly efficient code, and allows declarations.

The irony is that LOOP does the job it is supposed to do so well that
even tough I have tried various alternatives (eg iterate and doplus),
I still end up using LOOP.

Best,

Tamas

Juanjo Garcia

unread,
Mar 7, 2012, 8:55:52 AM3/7/12
to
On 7 mar, 13:26, Tamas Papp <tkp...@gmail.com> wrote:
> But the more I use LOOP, the more I long for a replacement,
> specifically one that is
>
> (1) extensible, preferably using itself as a DSL,

Keep in mind that extensibility usually works against uniformity/
portability.

> (2) handles destructuring, via an extensible destructuring library
> (like let+ or bind),

Same as above.

> (3) handles collection in an extensible manner.

I subscribe.

> (4) doesn't use a code walker,

It is a macro. I don't think it could be done differently.

> (5) compiles into fairly efficient code, and allows declarations.

It does both.

Marco Antoniotti

unread,
Mar 7, 2012, 10:46:01 AM3/7/12
to
On Wednesday, March 7, 2012 4:48:18 AM UTC-5, WJ wrote:
> In PCL, there is a chapter promoting the use of the COBOL-like
> LOOP. I think that the examples can be done more elegantly
> without LOOP by using NewLisp.

Yawn. Ronf. Ronf. Zzzzzzz!

Or better.

(loop while t do (format t "Yawn. Ronf. Ronf. Zzzzzzz! "))

--
MA

Marco Antoniotti

unread,
Mar 7, 2012, 10:43:11 AM3/7/12
to
On Wednesday, March 7, 2012 8:55:52 AM UTC-5, Juanjo Garcia wrote:
> On 7 mar, 13:26, Tamas Papp <tkp...@gmail.com> wrote:
> > But the more I use LOOP, the more I long for a replacement,
> > specifically one that is
> >
> > (1) extensible, preferably using itself as a DSL,
>
> Keep in mind that extensibility usually works against uniformity/
> portability.

Well, there where DEFINE-LOOP-PATH and friends at a certain point.

>
> > (2) handles destructuring, via an extensible destructuring library
> > (like let+ or bind),
>
> Same as above.

Or, shameless plug CL-UNIFICATION :)

>
> > (3) handles collection in an extensible manner.
>
> I subscribe.

(loop for x over (enum:enumerate a-red-black-tree) do ...) ; Not there yet!

Another http://common-lisp.net/project/cl-enumeration/ shameless plug :)

>
> > (4) doesn't use a code walker,
>
> It is a macro. I don't think it could be done differently.

Yep.

>
> > (5) compiles into fairly efficient code, and allows declarations.
>
> It does both.

Ditto. (loop for x of-type double-float in '(0.0d0 1.0d0 42.0d0) do ...)

Cheers
--
MA

Juanjo Garcia

unread,
Mar 7, 2012, 11:20:17 AM3/7/12
to
On 7 mar, 16:46, Marco Antoniotti <marc...@gmail.com> wrote:
> On Wednesday, March 7, 2012 4:48:18 AM UTC-5, WJ wrote:
> (loop while t do (format t "Yawn.  Ronf. Ronf. Zzzzzzz! "))
Correct, but more concisely:
(loop (format t "Yawn.  Ronf. Ronf. Zzzzzzz! "))

Marco Antoniotti

unread,
Mar 7, 2012, 11:32:40 AM3/7/12
to
I stand corrected. :)

--
MA

Fritz Wuehler

unread,
Mar 7, 2012, 11:44:06 AM3/7/12
to
> In PCL, there is a chapter promoting the use of the COBOL-like
> LOOP.

There is no loop in COBOL. Maybe the author was thinking of FORTRAN or
something else?

namekuseijin

unread,
Mar 7, 2012, 1:34:13 PM3/7/12
to
On Wednesday, March 7, 2012 8:50:55 AM UTC-3, Alex Mizrahi wrote:
> Elegance is a synthetic quality which includes readability, efficiency,
> terseness and cleverness. It is highly subjective, of course.

It is, but I'd still say:

head, tail, map, sequence (or range), for, while, repeat

are way more meaningful and readable for most people than idiossyncratic particularities of Lisp that are nothing but historic cruft:

car, cdr, mapcar, iota, loop for, loop while, loop repeat etc

> > (sequence 0 10)
> $ (sapa:iota 0 10 :type 'list)
> (0 1 2 3 4 5 6 7 8 9 10)

These are clearly not the same thing. One is a builtin with a meaningful name for most people outside Lisp, the other is a particular function from someone's lib who uses some stupid name that like most other Lisp names has some historical meaning lost in time.

The non-builtin function also features another problem of olde Lisps: its full of a myriad of optional arguments that you should look up in the documentation in order to use the function. Rather than just do 1 thing and 1 thing well, Lisp functions are kind of like kitchen sinks.

So, yeah, perhaps it is one more instance of "worse is better", except the "better" is really some overengineered Lisp idiom which got crust all over from the older cousins.

> > The low, loopy way:
> > (loop repeat 5
> > for x = 0 then y
> > for y = 1 then (+ x y)
> > collect y)
> > ==> (1 2 4 8 16)
> > The high way:
> >
> > (map (curry pow 2) (sequence 0 4))
> > ==> (1 2 4 8 16)
>
> You're comparing low-level, optimized LOOP to a non-optimized HoF
> version. It would be more correct to compare your code with this:
>
> (loop for i from 0 to 4
> collect (expt 2 i))

Fair enough. Still looks like a verbose and imperative C-for loop though.

BTW, why do all looping constructs need be encoded in this gigantic loop macro? Why write (loop for ...) or (loop while ...) or (loop repeat ...) rather than simply (for ...) (while ...) or (repeat ...)?

> $ (mapcar (curry #'expt 2) (iota 5))

mapcar. Car only has some meaning to Lispers and it seems only to archeologists in the near future. Just use map.

> Also, you're trying to frame this as CL vs newLISP, but CL can do all
> this stuff if you use some library.

yes, Lisp or any other turing-complete language can do something other turing-complete language can do by using functions in some library. And this is the main reason why CL and Scheme are old wigs now and have never quite managed to get the kind of software environment that java/python/perl/php got.

You can always write it yourself or grab what someone else wrote and thus the language itself never seems to evolve, because each person has their own ideas on what idiom they should use and thus don't agree with other people's ideas on the subject, as is the case of Scheme, or simply put everyone's (old) ideas into one big monolythic package known as CL. Since the language is either too bare (Scheme) or too complicated (CL) and you have to search non-official libs to get useful functionality into the language, almost nobody uses these languages for serious software development.

The Racket and Clojure guys did a good job by focusing on the specifics of their implementation and getting away from the Lisp name, comittees and historic cruft. Their relative success shows modernized Lisp can appeal to the masses.

Alex Mizrahi

unread,
Mar 7, 2012, 2:09:23 PM3/7/12
to
> It is, but I'd still say:

> head, tail, map, sequence (or range), for, while, repeat

> are way more meaningful and readable for most people than idiossyncratic particularities of Lisp that are nothing but historic cruft:

> car, cdr, mapcar, iota, loop for, loop while, loop repeat etc

I don't see why you inlude loop for/while/repeat with the rest of
'historic cruft'. It makes much more sense if you read it as plain
English -- loop is a verb here, for/while/repeat defines condition.
Just as you can say "stand while flag is set" you say "loop while flag",

It IS a verb:
http://www.merriam-webster.com/dictionary/loop?show=2&t=1331146820

On the other hand, use of condition without verb is just a historic
practice. Yes, a lot of programmers understand it, but same can be said
about any C-like language feature.

BTW in Pascal it is while ... do, for ... do, repeat .., until. Much
closer to plain English.

Marco Antoniotti

unread,
Mar 7, 2012, 2:33:08 PM3/7/12
to
He was thinking of INTERCAL (or Brainf**k; take your pick) :)

Cheers
--
MA

Marco Antoniotti

unread,
Mar 7, 2012, 2:47:32 PM3/7/12
to
On Wednesday, March 7, 2012 1:34:13 PM UTC-5, namekuseijin wrote:
> On Wednesday, March 7, 2012 8:50:55 AM UTC-3, Alex Mizrahi wrote:
> > Elegance is a synthetic quality which includes readability, efficiency,
> > terseness and cleverness. It is highly subjective, of course.
>
> It is, but I'd still say:
>
> head, tail, map, sequence (or range), for, while, repeat
>
> are way more meaningful and readable for most people than idiossyncratic particularities of Lisp that are nothing but historic cruft:
>
> car, cdr, mapcar, iota, loop for, loop while, loop repeat etc

first, rest, map are in CL as well.

The LOOP variants are no different that having the *SINGLE* entry points 'while', 'do', 'for'. This is a non-issue.

>
> > > (sequence 0 10)
> > $ (sapa:iota 0 10 :type 'list)
> > (0 1 2 3 4 5 6 7 8 9 10)
>
> These are clearly not the same thing. One is a builtin with a meaningful name for most people outside Lisp, the other is a particular function from someone's lib who uses some stupid name that like most other Lisp names has some historical meaning lost in time.

The distinction between "built-in" and "library" is moot.

> The non-builtin function also features another problem of olde Lisps: its full of a myriad of optional arguments that you should look up in the documentation in order to use the function. Rather than just do 1 thing and 1 thing well, Lisp functions are kind of like kitchen sinks.

It's because the 1-shot built-in are insufficient. Plus, you always end up writing complex 1-shot abstractions on top of 1-shot "simple" functions.

> So, yeah, perhaps it is one more instance of "worse is better", except the "better" is really some overengineered Lisp idiom which got crust all over from the older cousins.

I don't see any particular "over-engineered" stuff in CL. As a matter of fact there are several "under-engineered" parts.
>
> Fair enough. Still looks like a verbose and imperative C-for loop though.
>

If you have better alternatives...

> BTW, why do all looping constructs need be encoded in this gigantic loop macro? Why write (loop for ...) or (loop while ...) or (loop repeat ...) rather than simply (for ...) (while ...) or (repeat ...)?
>
> > $ (mapcar (curry #'expt 2) (iota 5))
>
> mapcar. Car only has some meaning to Lispers and it seems only to archeologists in the near future. Just use map.

And you can just use map

(map 'list (curry 'expt 2) (range 0 5))

> yes, Lisp or any other turing-complete language can do something other turing-complete language can do by using functions in some library. And this is the main reason why CL and Scheme are old wigs now and have never quite managed to get the kind of software environment that java/python/perl/php got.

We got Emacs. What else do you need?

> You can always write it yourself or grab what someone else wrote and thus the language itself never seems to evolve, because each person has their own ideas on what idiom they should use and thus don't agree with other people's ideas on the subject, as is the case of Scheme, or simply put everyone's (old) ideas into one big monolythic package known as CL. Since the language is either too bare (Scheme) or too complicated (CL) and you have to search non-official libs to get useful functionality into the language, almost nobody uses these languages for serious software development.

Define "non-official lib". AFAIC, if it is in quicklisp it is "official".

> The Racket and Clojure guys did a good job by focusing on the specifics of their implementation and getting away from the Lisp name, comittees and historic cruft. Their relative success shows modernized Lisp can appeal to the masses.

So: bottom line, we should just get rid of "Lisp". I find it more useful to write CL (or Haskell) code.

Cheers
--
MA

Teemu Likonen

unread,
Mar 7, 2012, 3:21:52 PM3/7/12
to
* <nameku...@gmail.com> [2012-03-07 10:34:13 -0800] wrote:

> BTW, why do all looping constructs need be encoded in this gigantic
> loop macro? Why write (loop for ...) or (loop while ...) or (loop
> repeat ...) rather than simply (for ...) (while ...) or (repeat ...)?

Because LOOP combines many features. How would you implement

(loop :repeat 10
:for count :upfrom 1
:for line := (read-line stream nil)
:while line
:do ...)

with "simple" and separate macros REPEAT, FOR and WHILE?

Tim Bradshaw

unread,
Mar 7, 2012, 3:59:10 PM3/7/12
to
Marco Antoniotti <mar...@gmail.com> wrote:

> He was thinking

He was?

Alessio Stalla

unread,
Mar 7, 2012, 5:10:47 PM3/7/12
to
On Mar 7, 1:26 pm, Tamas Papp <tkp...@gmail.com> wrote:
> But the more I use LOOP, the more I long for a replacement,
> specifically one that is
>
> (1) extensible, preferably using itself as a DSL,
>
> (2) handles destructuring, via an extensible destructuring library
> (like let+ or bind),
>
> (3) handles collection in an extensible manner.
>
> (4) doesn't use a code walker,
>
> (5) compiles into fairly efficient code, and allows declarations.

Shameless plug! Shameless plug! :D

doplus fully does (1), (3), and (4). It is a macro, and it CAN be done
differently ;)
It does (5) partly; it allows declarations, but it's not particularly
optimized, so I suppose the generated code could be more efficient.
Recently I added the possibility to disable atomic updates if you
don't need them; that should result in more efficient code, but I
haven't done any benchmarks.
Regarding (2), the question is: how/when do you plug in your own
destructuring library? Globally (but then different users of doplus
might clash)? Locally, per invocation (but then you introduce
boilerplate)? Per package? Per thread, via a dynamic variable (and at
build time users are supposed to bind it correctly)? (define-doplus-
variant my-do+ :with-destructuring-implementation ...) ?

If I get a reasonable answer to that, I'll implement it! But I haven't
been able to give myself a satisfying answer, and given that I do not
use (yet) any destructuring library in my own code, I didn't think too
hard about it.

> The irony is that LOOP does the job it is supposed to do so well that
> even tough I have tried various alternatives (eg iterate and doplus),
> I still end up using LOOP.

Me, I never remember the proper LOOP syntax; I constantly have to look
it up. And I hate that
(loop ... (with-foo (something) (collect something))) is not possible,
and that I have to write if ... then ... else ... rather than
(if ... ... ...), etc. etc. this is Lisp, damnit! But of course, in
the end it's a matter of personal preference.

Alessio

--
Some gratuitous spam:

http://ripple-project.org Ripple, social credit system
http://villages.cc Villages.cc, Ripple-powered community economy
http://common-lisp.net/project/armedbear ABCL, Common Lisp on the JVM
http://code.google.com/p/tapulli my current open source projects

namekuseijin

unread,
Mar 7, 2012, 6:05:46 PM3/7/12
to
I don't know, because looking at this mess I have not much clue what it is doing. Are the several fors running parallel or are they nested (and don't look like it)? Is repeat 10 repeating 10 times whatever comes after? Is this even true code that will compile or is this listing the features of loop?

In any case, it is not intuitive.

namekuseijin

unread,
Mar 7, 2012, 6:37:35 PM3/7/12
to
On Wednesday, March 7, 2012 4:47:32 PM UTC-3, Marco Antoniotti wrote:
> On Wednesday, March 7, 2012 1:34:13 PM UTC-5, namekuseijin wrote:
> > On Wednesday, March 7, 2012 8:50:55 AM UTC-3, Alex Mizrahi wrote:
> > > Elegance is a synthetic quality which includes readability, efficiency,
> > > terseness and cleverness. It is highly subjective, of course.
> >
> > It is, but I'd still say:
> >
> > head, tail, map, sequence (or range), for, while, repeat
> >
> > are way more meaningful and readable for most people than idiossyncratic particularities of Lisp that are nothing but historic cruft:
> >
> > car, cdr, mapcar, iota, loop for, loop while, loop repeat etc
>
> first, rest, map are in CL as well.
>
> The LOOP variants are no different that having the *SINGLE* entry points 'while', 'do', 'for'. This is a non-issue.

Everything is a non-issue for old Lispers.

> > > > (sequence 0 10)
> > > $ (sapa:iota 0 10 :type 'list)
> > > (0 1 2 3 4 5 6 7 8 9 10)
> >
> > These are clearly not the same thing. One is a builtin with a meaningful name for most people outside Lisp, the other is a particular function from someone's lib who uses some stupid name that like most other Lisp names has some historical meaning lost in time.
>
> The distinction between "built-in" and "library" is moot.

It is not. Yes, I know Lisp is supposed to be like a big giant ball that sucks whatever it rolls over. But it is not.

If you work on a big project and each module uses a similar function that behaves not quite the same and got different interface, it is a PITA. Treating functions from foreign libs, thus, is not the same as a builtin. A builtin everyone agrees with enforces code sharing and code reuse. This is something very rare in the Lisp world.

> > The non-builtin function also features another problem of olde Lisps: its full of a myriad of optional arguments that you should look up in the documentation in order to use the function. Rather than just do 1 thing and 1 thing well, Lisp functions are kind of like kitchen sinks.
>
> It's because the 1-shot built-in are insufficient. Plus, you always end up writing complex 1-shot abstractions on top of 1-shot "simple" functions.

That's the whole point of function composition.

> > Fair enough. Still looks like a verbose and imperative C-for loop though.
> >
>
> If you have better alternatives...

> > mapcar. Car only has some meaning to Lispers and it seems only to archeologists in the near future. Just use map.
>
> And you can just use map
>
> (map 'list (curry 'expt 2) (range 0 5))

yeah, but now you got an ugly extra arg there. range is also non-standard and depends of whatever your current lib provider thinks range should be. Possibly, like most Lisp devs, it may contain several extra arguments that are not the same as another's take on the same function.

> > yes, Lisp or any other turing-complete language can do something other turing-complete language can do by using functions in some library. And this is the main reason why CL and Scheme are old wigs now and have never quite managed to get the kind of software environment that java/python/perl/php got.
>
> We got Emacs. What else do you need?

I was talking about libs.

> So: bottom line, we should just get rid of "Lisp". I find it more useful to write CL (or Haskell) code.

get rid of cruft. and the weight behind a name.

Tim Bradshaw

unread,
Mar 7, 2012, 7:07:27 PM3/7/12
to
namekuseijin <nameku...@gmail.com> wrote:

> Everything is a non-issue for old Lispers.

But people who found there were better languages wouldn't waste their time
berating Lisp in Lisp newsgroups, would they, I mean that would be weird
and creepy. Oh.

Chiron

unread,
Mar 7, 2012, 8:32:05 PM3/7/12
to
On Wed, 07 Mar 2012 15:37:35 -0800, namekuseijin wrote:

> Everything is a non-issue for old Lispers.

You say that like it was a bad thing.

I don't know - maybe old Lispers are all idiots who don't know that
they're using a dumb language. OTOH, maybe they're not so dumb, and have
found a powerful tool that allows them to do pretty much everything they
need.

Personally, my guess is that they know something you don't know - and
apparently don't care to learn. But that's just me.

Fortunately, there is no need to learn lisp. Anyone who feels the
language isn't worthwhile can use something else, and never have to look
at another lisp program. Of course, if they keep on reading
comp.lang.lisp, this isn't going to work - they'll still see lisp.

--
"You're just the sort of person I imagined marrying, when I was little...
except, y'know, not green... and without all the patches of fungus."
-- Swamp Thing

WJ

unread,
Mar 7, 2012, 8:40:11 PM3/7/12
to
> (defparameter random (loop repeat 100 collect (random 10000)))
>
> (loop for i in random
> counting (evenp i) into evens
> counting (oddp i) into odds
> summing i into total
> maximizing i into max
> minimizing i into min
> finally (return (list min max total evens odds)))
>
> ==>
> (47 9964 543718 46 54)
>
>
> The high way:
>
> (setq random (rand 10000 100))
>
> (append
> (map (fn (f) (apply f random)) (list min max +))
> (map (fn (f) (length (filter f random))) (list even? odd?)))
>
> ==>
> (87 9996 522987 49 51)
>
>
>
> Here are the definitions of odd? and even?:
>
> (define (odd? n) (= 1 (% n 2)))
> (define (even? n) (not (odd? n)))

Paul Graham:

I consider Loop one of the worst flaws in CL, and an example
to be borne in mind by both macro writers and language designers.


Dan Weinreb, one of the designers of Common Lisp:

... the problem with LOOP was that it turned out to be hard to
predict what it would do, when you started using a lot of
different facets of LOOP all together. This is a serious problem
since the whole idea of LOOP was to let you use many facets
together; if you're not doing that, LOOP is overkill.

WJ

unread,
Mar 7, 2012, 8:55:02 PM3/7/12
to
> (defparameter random (loop repeat 100 collect (random 10000)))
>
> (loop for i in random
> counting (evenp i) into evens
> counting (oddp i) into odds
> summing i into total
> maximizing i into max
> minimizing i into min
> finally (return (list min max total evens odds)))
>
> ==>
> (47 9964 543718 46 54)
>
>
> The high way:
>
> (setq random (rand 10000 100))
>
> (append
> (map (fn (f) (apply f random)) (list min max +))
> (map (fn (f) (length (filter f random))) (list even? odd?)))
>
> ==>
> (87 9996 522987 49 51)
>


Here's what the experts say about COBOL Lisp:

"an unwieldy, overweight beast"
"intellectual overload"
"did kill Lisp"
"A monstrosity"
"ignores the basics of language design"
"killed Lisp"
"sucks"
"an aberration"
"incomprehensible"
"a nightmare"
"not commercially viable"
"no future"
"a significantly ugly language"
"hacks"
"unfortunate"
"bad"

In context:

Brooks and Gabriel 1984, "A Critique of Common Lisp":

Every decision of the committee can be locally rationalized
as the right thing. We believe that the sum of these
decisions, however, has produced something greater than its
parts; an unwieldy, overweight beast, with significant costs
(especially on other than micro-codable personal Lisp
engines) in compiler size and speed, in runtime performance,
in programmer overhead needed to produce efficient programs,
and in intellectual overload for a programmer wishing to be
a proficient COMMON LISP programmer.


-----


Bernard Lang:

Common Lisp did kill Lisp. Period. (just languages take a
long time dying ...) It is to Lisp what C++ is to C. A
monstrosity that totally ignores the basics of language
design, simplicity and orthogonality to begin with.


-----

Gilles Kahn:

To this day I have not forgotten that Common Lisp killed
Lisp, and forced us to abandon a perfectly good system,
LeLisp.

-----


Paul Graham, May 2001:

A hacker's language is terse and hackable. Common Lisp is not.

The good news is, it's not Lisp that sucks, but Common Lisp.

Historically, Lisp has been good at letting hackers have their
way. The political correctness of Common Lisp is an aberration.
Early Lisps let you get your hands on everything.

A really good language should be both clean and dirty:
cleanly designed, with a small core of well understood and
highly orthogonal operators, but dirty in the sense that it
lets hackers have their way with it. C is like this. So were
the early Lisps. A real hacker's language will always have a
slightly raffish character.

Organic growth seems to yield better technology and richer
founders than the big bang method. If you look at the
dominant technologies today, you'll find that most of them
grew organically. This pattern doesn't only apply to
companies. You see it in sponsored research too. Multics and
Common Lisp were big-bang projects, and Unix and MacLisp
were organic growth projects.


-----

Jeffrey M. Jacobs:


Common LISP is the PL/I of Lisps. Too big and too
incomprehensible, with no examination of the real world of
software engineering.

... The CL effort resembles a bunch of spoiled children,
each insisting "include my feature or I'll pull out, and
then we'll all go down the tubes". Everybody had vested
interests, both financial and emotional.

CL is a nightmare; it has effectively killed LISP
development in this country. It is not commercially viable
and has virtually no future outside of the traditional
academic/defense/research arena.


-----


Dick Gabriel:

Common Lisp is a significantly ugly language. If Guy and I
had been locked in a room, you can bet it wouldn't have
turned out like that.


-----

Paul Graham:

Do you really think people in 1000 years want to be
constrained by hacks that got put into the foundations of
Common Lisp because a lot of code at Symbolics depended on
it in 1988?


-----

Daniel Weinreb, 24 Feb 2003:

Having separate "value cells" and "function cells" (to use
the "street language" way of saying it) was one of the most
unfortunate issues. We did not want to break pre-existing
programs that had a global variable named "foo" and a global
function named "foo" that were distinct. We at Symbolics
were forced to insist on this, in the face of everyone's
knowing that it was not what we would have done absent
compatibility constraints. It's hard for me to remember all
the specific things like this, but if we had had fewer
compatibility issues, I think it would have come out looking
more like Scheme in general.


-----

Daniel Weinreb, 28 Feb 2003:

Lisp2 means that all kinds of language primitives have to
exist in two versions, or be parameterizable as to whether
they are talking about the value cell or function cell. It
makes the language bigger, and that's bad in and of itself.

-----

Guy L. Steele, Jr., July 1989:

I think we may usefully compare the approximate number of pages
in the defining standard or draft standard for several
programming languages:

Common Lisp 1000 or more
COBOL 810
ATLAS 790
Fortran 77 430
PL/I 420
BASIC 360
ADA 340
Fortran 8x 300
C 220
Pascal 120
DIBOL 90
Scheme 50

Don Geddis

unread,
Mar 7, 2012, 9:55:55 PM3/7/12
to
If you know NOTHING about LOOP, then sure, you need to learn at least
the first few sentences of the description.

All the stepping of the clauses happen in parallel. (They don't look
nested, because ... they aren't. See how easy that was?)

> In any case, it is not intuitive.

It's a complex iteration. It won't be "intuitive" in any language, if
you haven't the first clue what the language constructs do.

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org
If you ever get whipped by a bullwhip, try to breathe _in_ as the whip is going
back, and _out_ as it hits your back. Or is it the other way around? Anyway,
you'll figure it out. -- Deep Thoughts, by Jack Handey [1999]

Marco Antoniotti

unread,
Mar 7, 2012, 10:48:52 PM3/7/12
to
On Wednesday, March 7, 2012 6:37:35 PM UTC-5, namekuseijin wrote:
> On Wednesday, March 7, 2012 4:47:32 PM UTC-3, Marco Antoniotti wrote:
> > On Wednesday, March 7, 2012 1:34:13 PM UTC-5, namekuseijin wrote:
> > > On Wednesday, March 7, 2012 8:50:55 AM UTC-3, Alex Mizrahi wrote:
> > > > Elegance is a synthetic quality which includes readability, efficiency,
> > > > terseness and cleverness. It is highly subjective, of course.
> > >
> > > It is, but I'd still say:
> > >
> > > head, tail, map, sequence (or range), for, while, repeat
> > >
> > > are way more meaningful and readable for most people than idiossyncratic particularities of Lisp that are nothing but historic cruft:
> > >
> > > car, cdr, mapcar, iota, loop for, loop while, loop repeat etc
> >
> > first, rest, map are in CL as well.
> >
> > The LOOP variants are no different that having the *SINGLE* entry points 'while', 'do', 'for'. This is a non-issue.
>
> Everything is a non-issue for old Lispers.

It is not, because you can (and you do) have it both ways.


> > > > > (sequence 0 10)
> > > > $ (sapa:iota 0 10 :type 'list)
> > > > (0 1 2 3 4 5 6 7 8 9 10)
> > >
> > > These are clearly not the same thing. One is a builtin with a meaningful name for most people outside Lisp, the other is a particular function from someone's lib who uses some stupid name that like most other Lisp names has some historical meaning lost in time.
> >
> > The distinction between "built-in" and "library" is moot.
>
> It is not. Yes, I know Lisp is supposed to be like a big giant ball that sucks whatever it rolls over. But it is not.
>
> If you work on a big project and each module uses a similar function that behaves not quite the same and got different interface, it is a PITA. Treating functions from foreign libs, thus, is not the same as a builtin. A builtin everyone agrees with enforces code sharing and code reuse. This is something very rare in the Lisp world.

So. WJ says that GLS says that the 1000 ANSI standard is too big. Which is which? I am confused...



>
> > > The non-builtin function also features another problem of olde Lisps: its full of a myriad of optional arguments that you should look up in the documentation in order to use the function. Rather than just do 1 thing and 1 thing well, Lisp functions are kind of like kitchen sinks.
> >
> > It's because the 1-shot built-in are insufficient. Plus, you always end up writing complex 1-shot abstractions on top of 1-shot "simple" functions.
>
> That's the whole point of function composition.

Something that apparently you cannot do in Common Lisp.

>
> > > Fair enough. Still looks like a verbose and imperative C-for loop though.
> > >
> >
> > If you have better alternatives...
>
> > > mapcar. Car only has some meaning to Lispers and it seems only to archeologists in the near future. Just use map.
> >
> > And you can just use map
> >
> > (map 'list (curry 'expt 2) (range 0 5))
>
> yeah, but now you got an ugly extra arg there. range is also non-standard and depends of whatever your current lib provider thinks range should be. Possibly, like most Lisp devs, it may contain several extra arguments that are not the same as another's take on the same function.

The problem is that you want it "simpler than simple". You just want MAP, but then you would be very happy to do

(as-vector (map (curry 'expt 2) (range 0 5)) ; Or something like that.

You have made "I want it simpler than simple" remarks in the past if memory serves me well. I don't find them particularly compelling, especially because they usually fall short of considering all the ramifications of the simplification you propose.

> > > yes, Lisp or any other turing-complete language can do something other turing-complete language can do by using functions in some library. And this is the main reason why CL and Scheme are old wigs now and have never quite managed to get the kind of software environment that java/python/perl/php got.
> >
> > We got Emacs. What else do you need?
>
> I was talking about libs.

You have quicklisp, what else do you need.

>
> > So: bottom line, we should just get rid of "Lisp". I find it more useful to write CL (or Haskell) code.
>
> get rid of cruft. and the weight behind a name.

Define "cruft". As long as it is different from "minor syntactic issues you don't like" or "you should have a Lisp-1" or "you should have methods *in* classes". You can still find *a lot* of cruft, but it is not the kind that seems to bother you.

Cheers
--
MA

namekuseijin

unread,
Mar 7, 2012, 11:56:11 PM3/7/12
to
Em quarta-feira, 7 de março de 2012 23h55min55s UTC-3, Don Geddis escreveu:
> namekuseijin <nameku...@gmail.com> wrote on Wed, 7 Mar 2012 :
> > On Wednesday, March 7, 2012 5:21:52 PM UTC-3, Teemu Likonen wrote:
> >> (loop :repeat 10
> >> :for count :upfrom 1
> >> :for line := (read-line stream nil)
> >> :while line
> >> :do ...)
> >> with "simple" and separate macros REPEAT, FOR and WHILE?
> >
> > I don't know, because looking at this mess I have not much clue what
> > it is doing. Are the several fors running parallel or are they nested
> > (and don't look like it)? Is repeat 10 repeating 10 times whatever
> > comes after? Is this even true code that will compile or is this
> > listing the features of loop?
>
> If you know NOTHING about LOOP, then sure, you need to learn at least
> the first few sentences of the description.
>
> All the stepping of the clauses happen in parallel. (They don't look
> nested, because ... they aren't. See how easy that was?)

Easy enough when looking up docs, but not intuitive at all. AS all lispers know, (a list of things) is actually (a (list (of (things nil)))). Nesting is the rule.

so, how do you deal with nested loops? (loop for i from 1 to 10 (loop for j from 1 to i ...) ...)?

It's just rhetoric. I don't really care for such cruft.

> > In any case, it is not intuitive.
>
> It's a complex iteration. It won't be "intuitive" in any language, if
> you haven't the first clue what the language constructs do.

looping is a simple and intuitive construct in any language but CL, where it's an exercise in frustration but in the simplest case (whose syntax I've forgotten already).

WJ hits the nail with his compilation of sayings below.

namekuseijin

unread,
Mar 8, 2012, 12:16:32 AM3/8/12
to
Em quinta-feira, 8 de março de 2012 00h48min52s UTC-3, Marco Antoniotti escreveu:
> On Wednesday, March 7, 2012 6:37:35 PM UTC-5, namekuseijin wrote:
> > On Wednesday, March 7, 2012 4:47:32 PM UTC-3, Marco Antoniotti wrote:
> > > On Wednesday, March 7, 2012 1:34:13 PM UTC-5, namekuseijin wrote:
> > > > On Wednesday, March 7, 2012 8:50:55 AM UTC-3, Alex Mizrahi wrote:
> > > > > > (sequence 0 10)
> > > > > $ (sapa:iota 0 10 :type 'list)
> > > > > (0 1 2 3 4 5 6 7 8 9 10)
> > > >
> > > > These are clearly not the same thing. One is a builtin with a meaningful name for most people outside Lisp, the other is a particular function from someone's lib who uses some stupid name that like most other Lisp names has some historical meaning lost in time.
> > >
> > > The distinction between "built-in" and "library" is moot.
> >
> > It is not. Yes, I know Lisp is supposed to be like a big giant ball that sucks whatever it rolls over. But it is not.
> >
> > If you work on a big project and each module uses a similar function that behaves not quite the same and got different interface, it is a PITA. Treating functions from foreign libs, thus, is not the same as a builtin. A builtin everyone agrees with enforces code sharing and code reuse. This is something very rare in the Lisp world.
>
> So. WJ says that GLS says that the 1000 ANSI standard is too big. Which is which? I am confused...

It's too big because it's a frankenstein made of patches from the dozens of Lisps from the 70's. That also explains why it smells funny.

> > > > mapcar. Car only has some meaning to Lispers and it seems only to archeologists in the near future. Just use map.
> > >
> > > And you can just use map
> > >
> > > (map 'list (curry 'expt 2) (range 0 5))
> >
> > yeah, but now you got an ugly extra arg there. range is also non-standard and depends of whatever your current lib provider thinks range should be. Possibly, like most Lisp devs, it may contain several extra arguments that are not the same as another's take on the same function.
>
> The problem is that you want it "simpler than simple". You just want MAP, but then you would be very happy to do
>
> (as-vector (map (curry 'expt 2) (range 0 5)) ; Or something like that.

this is typical CLers talk, making something rarely used have the same weight as the general case. That's how you got cruft in the first place.

mapcar is an aberration and map taking as a stupid first argument a symbol saying what type of collection the mapping should generate is laughable. Wouldn't it be better if map was simply usable over sequences all the same?

besides, are you really complaining about an extra pair of Lisp's parentheses there as accounting for "complexity"?

> You have made "I want it simpler than simple" remarks in the past if memory serves me well. I don't find them particularly compelling, especially because they usually fall short of considering all the ramifications of the simplification you propose.

go read the complains about CL WJ posted below. Though I'm sure its old news to you and wont change your taste for that koolaid...
*edit* oh, you did already...

> > get rid of cruft. and the weight behind a name.
>
> Define "cruft".

all that jazz from now deceased lisps that one way or the other had to go into CL.

namekuseijin

unread,
Mar 8, 2012, 12:24:33 AM3/8/12
to
Em quarta-feira, 7 de março de 2012 22h32min05s UTC-3, Chiron escreveu:
> Personally, my guess is that they know something you don't know - and
> apparently don't care to learn. But that's just me.

yes, they know an utterly complex language that took them all their lifes to master and sure as hell won't drop it now, much like C++ slaves.

The only difference is that C++ is still adding more languages into it, while CL is, fortunately, roting.

> Fortunately, there is no need to learn lisp. Anyone who feels the
> language isn't worthwhile can use something else, and never have to look
> at another lisp program.

we hang on comp.lang.lisp because we think Lisp is worthwhile without all the cruft from ages past. We just don't like the CL zombie.

Chiron

unread,
Mar 8, 2012, 2:08:25 AM3/8/12
to
On Wed, 07 Mar 2012 21:24:33 -0800, namekuseijin wrote:

> Em quarta-feira, 7 de março de 2012 22h32min05s UTC-3, Chiron escreveu:
>> Personally, my guess is that they know something you don't know - and
>> apparently don't care to learn. But that's just me.
>
> yes, they know an utterly complex language that took them all their
> lifes to master and sure as hell won't drop it now, much like C++
> slaves.
>
I don't think that's a feature or problem of lisp. Just about everyone
tries to hang on to what they know. I'm not sure that's such a bad
thing. True - it is a *very* bad thing if a person clings to old ways
that are no longer useful; but lisp still seems to be useful to a lot of
people. Not sure exactly why that is, but that's what it seems.


> The only difference is that C++ is still adding more languages into it,
> while CL is, fortunately, roting.
>
>> Fortunately, there is no need to learn lisp. Anyone who feels the
>> language isn't worthwhile can use something else, and never have to
>> look at another lisp program.
>
> we hang on comp.lang.lisp because we think Lisp is worthwhile without
> all the cruft from ages past. We just don't like the CL zombie.

So, then, is your objection to CL specifically, but you're OK with some
other (perhaps not yet implemented) version of lisp? Is there even such
a version? What you describe sounds less like a dialect of lisp, and
more like an entirely different language. I wonder where the boundaries
are...

Ah, well. Boa noite.


--
<Overfiend> The Unix way -- everything is a file
<Overfiend> The Linux way -- everything is a filesystem :)

Nicolas Neuss

unread,
Mar 8, 2012, 2:46:06 AM3/8/12
to
Alessio Stalla <alessi...@gmail.com> writes:

> Me, I never remember the proper LOOP syntax; I constantly have to look
> it up.

At least, from time to time this is true for me as well, although I
like loop (mostly).

> And I hate that (loop ... (with-foo (something) (collect something)))
> is not possible, and that I have to write if ... then ... else
> ... rather than (if ... ... ...), etc. etc. this is Lisp, damnit!

Exactly! For me, it is a nice proof for the fact that Lisp can be
turned into anyting. When I once gave a introductory course about
programming, I showed in the last 5 minutes of each course how the
factorial function looked in some computer language (extreme cases were
Assembler, Lambda calculus and the Turing machine). For Common Lisp I
showed several possibilities (attached below) each corresponding to a
certain programming style. And the loop solution represented the
COBOL-like style where you try to approximate natural language.

> But of course, in the end it's a matter of personal preference.
>
> Alessio

Nicolas


;;; Standard
(defun factorial (n)
(if (= n 0)
1
(* n (factorial (- n 1)))))

;;; with LOOP
(defun factorial (n)
(loop for i from 1 upto n
and f = 1 then (* f i)
finally (return f)))

;;; with CLOS
(defmethod factorial ((n (eql 0)))
1)
(defmethod factorial ((n integer))
(* n (factorial (- n 1))))

;;; with infix library
(defun factorial (n)
#I"if (n==0) then
1
else
n*factorial(n-1)")

;;; like C
(defun factorial (n)
(declare (type fixnum n) (values fixnum))
(declare (optimize (safety 0) (speed 3)))
(if (= n 0)
1
(* n (factorial (- n 1)))))

(factorial 17) ; gives wrong solution like C (on 32bit hardware)

Teemu Likonen

unread,
Mar 8, 2012, 3:31:18 AM3/8/12
to
* Alessio Stalla [2012-03-07 14:10:47 -0800] wrote:

> And I hate that
> (loop ... (with-foo (something) (collect something))) is not possible,

It's a disadvantage but as this is Common Lisp extending the language is
simple enough.


(ql:quickload :general-accumulator) ; [link]

(genacc:with-accumulator (collect :list)
(loop ...
:do (with-fancy-stuff ... (collect whatever) ...)
:finally (return (collect))))


(When LOOP's COLLECT is not enough.)

My ultimate point is that everything is not perfect in the language but
many things are trivial to fix. Of course you all know this, but I fail
to understand why there's so much discussion about this.

--------------------
link: https://github.com/tlikonen/cl-general-accumulator

Alex Mizrahi

unread,
Mar 8, 2012, 3:54:47 AM3/8/12
to
> These are clearly not the same thing. One is a builtin with a meaningful name for most people outside Lisp,
> the other is a particular function from someone's lib who
> uses some stupid name that like most other

Nothing stops you from implementing your own shortcut. It isn't like
it's some fundamental feature which requires language support. If you're
picky about names and parameters, it's clearly a better way for you.

BTW, name comes from APL http://en.wikipedia.org/wiki/Iota:

The iota symbol is used to generate a vector of consecutive integers in
the APL programming language.
The name "iota" denotes a pseudo-constant to represent successive
integers in the Go programming language.

I guess it comes from math notation: i = 0..10
Yeah, totally obscure meaning...

> The non-builtin function also features another problem of olde Lisps: its full of a myriad of optional arguments that you should look up in the documentation in order to use the function.

Only if you're a braindamaged moron. If you use a decent IDE (SLIME), it
shows parameter list:

(defun iota (start end &key (type 'vector)

Fairly straightforward, no?

Alexandria's iota is even simpler:

(defun iota (n &key (start 0) (step 1))

> Rather than just do 1 thing and 1 thing well,

You demonstrate total lack of understanding math: if a function has two
parameters and each parameter accept two options, then you have 2*2
modes, so you need 4 functions to do same thing. With more parameters
and more options it quickly gets out of control.

So either you need parametrization or you need composable primitives.
LOOP provides these composable primitives through a sublanguage.

Some people argue that we don't need this and can use simple functions
or higher order functions. While it is true, functional solutions often
are non-obvious and/or are cumbersome.

It is somewhat alleviated in languages which has first-class currying
and lazy evaluation, such as Haskell. But even there, it makes code very
dense and rather hard to read. (But some people like it that way.)

However if you have to write curry explicitly it's a joke compared to
other control structures.

>> (loop for i from 0 to 4
>> collect (expt 2 i))
> Fair enough. Still looks like a verbose and imperative C-for loop though.

It looks like something from math for me. Which is actually good if it
is math code.

> BTW, why do all looping constructs need be encoded in this gigantic loop macro?

Because it is easier to compose them that way. And because it is easier
to spot loop.

> yes, Lisp or any other turing-complete language can do something other turing-complete language
> can do by using functions in some library.

This isn't true. Last time I've checked, newLISP doesn't have a proper
garbage collector. You can't add garbage collector as a library.

Likewise, it's pretty hard to have deterministic memory management in
CL. It simply can't work portably, and if you do this for a certain
implementation, it would mutilate all your code.

There is a lot of language traits which are fairly hard to add:
continuations, exceptions, polymorphism for built-in functions, list
comprehensions and so on.

However, things we are talking about are very simple utility functions.
There is absolutely no problem with adding your own in scope of your
project.

> And this is the main reason why CL and Scheme are old wigs now and have never quite managed to get the kind of software environment that java/python/perl/php got.

They got better?

> You can always write it yourself or grab what someone else wrote and thus the language itself never seems to evolve,

It's a feature, not a bug. Java/Perl/Python/PHP programmers always have
to clarify version of language, CL programmers don't.

Also, Scheme went through many revisions, I fail to see how it "never
seems to evolve".

> Since the language is either too bare (Scheme)

Racket is non-bare Scheme. So?

> or too complicated (CL) and you have to search non-official libs to get useful functionality into the language,

There are languages where all useful functionality is only in official
libs? I'd rather stay away from it.

Common Lisp libs are mostly agnostic of CL implementation and version,
so I don't have to update libs -- and my code accordingly -- when I use
different version or vendor.

But if you use official libs you also subscribe to official library
updates. That's why C# programmers think in terms of .NET frameworks,
not in terms of C#.

> The Racket

Racket is an evolved Scheme, no?

> and Clojure guys did a good job by focusing on the specifics of their implementation and getting away from the Lisp name, comittees and historic cruft.

What historic cruft Racket got rid of? As far as I understand, they aim
to make a simple, yet practical language. Of course you don't want
comittee into this.

> Their relative success shows modernized Lisp can appeal to the masses.

Which isn't necessary a good thing. Masses fall for fads and buzzwords.
Clojure promised parallel programming through immutable data structures
and software transactions, but I'm yet to see any benchmarks which
clearly proves an advantage.

Alex Mizrahi

unread,
Mar 8, 2012, 4:17:15 AM3/8/12
to
> In any case, it is not intuitive.

Look, dude, programming is hard. It is hard even if you understand the
language very well: you aren't supposed to look at complex code and
immediately understand what it does and how it does it. You need to read
and analyze it.
But if you don't even understand a language, that's a joke. Every
language has constructs which you simply need to learn. But, ironically,
LOOP can be read as plain English in many cases. Not all.

But let's go back to code Teemu wrote:

> (loop :repeat 10
> :for count :upfrom 1
> :for line := (read-line stream nil)
> :while line
> :do ...)
>

Write an analog in a language of your choice (preferably CL without
LOOP). And I'll show you how it is way worse than LOOP.

LOOP actually shines when you need at the same time
1) multiple termination conditions
2) iteration over multiple wars
3) conditional summing or collecting

Other ways to do it:
* tail recursion with accumulator -- "not intuitive", might be cumbersome
* imperative code with non-local transfer of control and imperative
aggregation (e.g. incf) -- more verbose, cumbersome, harder to read
* multiple map passes over temporary lists -- inefficient in non-lazy
languages, cannot work with side effects

Teemu Likonen

unread,
Mar 8, 2012, 4:19:46 AM3/8/12
to
* <nameku...@gmail.com> [2012-03-07 15:05:46 -0800] wrote:

> On Wednesday, March 7, 2012 5:21:52 PM UTC-3, Teemu Likonen wrote:
>> Because LOOP combines many features. How would you implement
>>
>> (loop :repeat 10
>> :for count :upfrom 1
>> :for line := (read-line stream nil)
>> :while line
>> :do ...)
>>
>> with "simple" and separate macros REPEAT, FOR and WHILE?
>
> I don't know, because looking at this mess I have not much clue what
> it is doing.

Believe me, you'd create a much bigger mess with simple REPEAT, FOR and
WHILE macros. In the real world there are many complex iteration tasks
and I think LOOP is a pretty simple answer for most of them.

There are some good criticism about LOOP but it doesn't tend to come
from programmers who only know Blub language's [link] iteration
constructs.

> Is this even true code that will compile [...]

Yes, except the "..." part after ":do".


--------------------
link: http://www.paulgraham.com/avg.html

Pascal J. Bourguignon

unread,
Mar 8, 2012, 5:06:23 AM3/8/12
to
namekuseijin <nameku...@gmail.com> writes:

> we hang on comp.lang.lisp because we think Lisp is worthwhile without
> all the cruft from ages past. We just don't like the CL zombie.

(defpackage "MODERN-LISP"
(:use "CL")
(:export "FIRST" ; not "CAR"
"REST" ; not "CDR"
"SETF"
…))

(defpackage "MY-PROGRAM"
(:use "MODERN-LISP"))
(in-package "MY-PROGRAM")

(first '(1 2 3))

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

Tim Bradshaw

unread,
Mar 8, 2012, 5:45:54 AM3/8/12
to
namekuseijin <nameku...@gmail.com> wrote:

> looping is a simple and intuitive construct in any language but CL, where
> it's an exercise in frustration but in the simplest case (whose syntax
> I've forgotten already).
>

We get that you don't like LOOP. So do the obvious thing: design and
implement a replacement. Many people have done this, and many of their
replacements are pretty good. Just sitting there whining is so *boring*.

noname

unread,
Mar 8, 2012, 6:42:04 AM3/8/12
to
Not that I intend or care to prove anything, but here is an
alternative implementation which I guess fits into the "tail recursion
with accumulator" type of solution:

(labels ((dowork (count &aux (line (read stream nil)))
(when (and line (plusp count))
;; do block
(work (1- count)))))
(dowork 10))

Isn't Clojure using similar approaches precisely because it lacks a
loop-like macro in order to be more "functional"?

I would argue that if programmers would start out with Scheme instead of
some C-like language then they would find the loop version less
intuitive.

Tim Bradshaw

unread,
Mar 8, 2012, 7:47:06 AM3/8/12
to
noname <blan...@noname.i-did-not-set--mail-host-address--so-tickle-me>
wrote:

> I would argue that if programmers would start out with Scheme instead of
> some C-like language then they would find the loop version less
> intuitive.

When I used to have more time (and when people used to post homework
questions more in newsgroups) I used to entertain myself by posting
tail-recursive answers to questions where there was looping going on. Now,
obviously, my answers were deliberately obscure, but I think there's a real
point here: it is not only possible, but quite easy to write code which is
impossibly obscure and hard to understand by using tail calls, while being
able to claim that the code is somehow "pure".

The same, of course, is exponentially true of first-class continuations.

Alessio Stalla

unread,
Mar 8, 2012, 8:07:36 AM3/8/12
to
On Mar 8, 9:31 am, Teemu Likonen <tliko...@iki.fi> wrote:
> * Alessio Stalla [2012-03-07 14:10:47 -0800] wrote:
>
> > And I hate that
> > (loop ... (with-foo (something) (collect something))) is not possible,
>
> It's a disadvantage but as this is Common Lisp extending the language is
> simple enough.

That's what I did: I extended the language adding my own high-level
loop construct.

>
>     (ql:quickload :general-accumulator) ; [link]
>
>     (genacc:with-accumulator (collect :list)
>       (loop ...
>             :do (with-fancy-stuff ... (collect whatever) ...)
>             :finally (return (collect))))
>
> (When LOOP's COLLECT is not enough.)
>
> My ultimate point is that everything is not perfect in the language but
> many things are trivial to fix. Of course you all know this, but I fail
> to understand why there's so much discussion about this.

Yes, my point is that LOOP is (for me) so often not enough that I
wrote a replacement. In C I would have been screwed, but in Lisp we
have the freedom to extend the language, and that's good.

Juanjo Garcia

unread,
Mar 8, 2012, 8:49:14 AM3/8/12
to
On 8 mar, 13:47, Tim Bradshaw <t...@tfeb.org> wrote:
> I used to entertain myself by posting
> tail-recursive answers to questions where there was looping going on.  Now,
> obviously, my answers were deliberately obscure, but I think there's a real
> point here: it is not only possible, but quite easy to write code which is
> impossibly obscure and hard to understand by using tail calls, while being
> able to claim that the code is somehow "pure".
>
> The same, of course, is exponentially true of first-class continuations.

Frequently, the extra intellectual effort required to understand
obfuscated code causes the brain to get a final triumph
sensation that can be misinterpreted as caused by the code being
more elegant/pure/whatever. (Another case of "worse is better"
scenario.)

Google for "The story of Mel" as yet another example.

Wonder if this mental phenomenon can explain, at least in part, why
people favor lesser programming languages.

Chiron

unread,
Mar 8, 2012, 9:11:32 AM3/8/12
to
On Thu, 08 Mar 2012 05:49:14 -0800, Juanjo Garcia wrote:

> Wonder if this mental phenomenon can explain, at least in part, why
> people favor lesser programming languages.


A "lesser" programming language? I dunno... I don't see many people
favoring COBOL, and I'd say that's pretty clearly a "lesser" language.
As for others - well, I think often it's a matter of taste rather than
some objective criterion for what makes a language "lesser."


--
The biggest difference between time and space is that you can't reuse
time.
-- Merrick Furst






--
It's easy to get on the internet and forget you have a life
-- Topic on #LinuxGER

Tim Bradshaw

unread,
Mar 8, 2012, 9:49:40 AM3/8/12
to
Juanjo Garcia <kod...@gmail.com> wrote:

> Wonder if this mental phenomenon can explain, at least in part, why
> people favor lesser programming languages.

I think it certainly does in part. I think the difference is whether
you're interested in the language as a language, or as a tool for getting
something done. If it's a tool, then you probably don't want it to be too
demanding to understand, even if the demanding bit is what makes it
interesting as a language. And, if it's a tool, it's not hard to learn
lots of rules each of which is not that hard to understand: when I wrote CL
full-time, I could create really hairy FORMAT strings without blinking,
because I did it often enough that I knew a lot of the constructs. The same
is true for LOOP, of course: there are lots of rules, but if you use it a
lot you end up knowing the ones that apply to you, and none of them are
hard. But as a language, sure, it's a mess: and that's fine.

The example this always brings to mind is Dirac delta functions. If you
want to understand what these are mathematically, you have to understand
all sorts of hairy stuff about distributions. But if you want to just get
stuff done in physics, you can just use them as a tool with some
more-or-less well-understood conditions on their use and skate over the
fact that none of it really makes formal sense: they were good enough for
Dirac, after all, so they probably are good enough for you. And that's
just fine.

Pascal J. Bourguignon

unread,
Mar 8, 2012, 10:34:37 AM3/8/12
to
Chiron <chiron613.no.spam.@no.spam.please.gmail.com> writes:

> The biggest difference between time and space is that you can't reuse
> time.
> -- Merrick Furst

Clearly wrong.

If you take two people and put them in different space, you can have
them do two things at the same time. That's a clear instance of time
reuse.

On the contrary, you can hardly put two different persons in the same
space: there's no reuse of space, at least for fermion-like persons.

Alessio Stalla

unread,
Mar 8, 2012, 10:37:08 AM3/8/12
to
On Mar 8, 4:34 pm, "Pascal J. Bourguignon" <p...@informatimago.com>
wrote:
> Chiron <chiron613.no.sp...@no.spam.please.gmail.com> writes:
> > The biggest difference between time and space is that you can't reuse
> > time.
> >            -- Merrick Furst
>
> Clearly wrong.
>
> If you take two people and put them in different space, you can have
> them do two things at the same time.  That's a clear instance of time
> reuse.
>
> On the contrary, you can hardly put two different persons in the same
> space: there's no reuse of space, at least for fermion-like persons.

Actually you can put two different persons in the same space - as long
as it's not at the same time ;)

Marco Antoniotti

unread,
Mar 8, 2012, 11:15:57 AM3/8/12
to
On Thursday, March 8, 2012 12:16:32 AM UTC-5, namekuseijin wrote:
> Em quinta-feira, 8 de março de 2012 00h48min52s UTC-3, Marco Antoniotti escreveu:
> > On Wednesday, March 7, 2012 6:37:35 PM UTC-5, namekuseijin wrote:
> > > On Wednesday, March 7, 2012 4:47:32 PM UTC-3, Marco Antoniotti wrote:
> > > > On Wednesday, March 7, 2012 1:34:13 PM UTC-5, namekuseijin wrote:
> > > > > On Wednesday, March 7, 2012 8:50:55 AM UTC-3, Alex Mizrahi wrote:
> > > > > > > (sequence 0 10)
> > > > > > $ (sapa:iota 0 10 :type 'list)
> > > > > > (0 1 2 3 4 5 6 7 8 9 10)
> > > > >
> > > > > These are clearly not the same thing. One is a builtin with a meaningful name for most people outside Lisp, the other is a particular function from someone's lib who uses some stupid name that like most other Lisp names has some historical meaning lost in time.
> > > >
> > > > The distinction between "built-in" and "library" is moot.
> > >
> > > It is not. Yes, I know Lisp is supposed to be like a big giant ball that sucks whatever it rolls over. But it is not.
> > >
> > > If you work on a big project and each module uses a similar function that behaves not quite the same and got different interface, it is a PITA. Treating functions from foreign libs, thus, is not the same as a builtin. A builtin everyone agrees with enforces code sharing and code reuse. This is something very rare in the Lisp world.
> >
> > So. WJ says that GLS says that the 1000 ANSI standard is too big. Which is which? I am confused...
>
> It's too big because it's a frankenstein made of patches from the dozens of Lisps from the 70's. That also explains why it smells funny.

Oh well. The real difference is that the RBTs ("really bad things") of CL are other ones. Pathnames and case are my favorites (and Franz "modern mode" is another one). Naming variations and really minor function signatures are really small fry compared to those warts.

> > > > > mapcar. Car only has some meaning to Lispers and it seems only to archeologists in the near future. Just use map.
> > > >
> > > > And you can just use map
> > > >
> > > > (map 'list (curry 'expt 2) (range 0 5))
> > >
> > > yeah, but now you got an ugly extra arg there. range is also non-standard and depends of whatever your current lib provider thinks range should be. Possibly, like most Lisp devs, it may contain several extra arguments that are not the same as another's take on the same function.
> >
> > The problem is that you want it "simpler than simple". You just want MAP, but then you would be very happy to do
> >
> > (as-vector (map (curry 'expt 2) (range 0 5)) ; Or something like that.
>
> this is typical CLers talk, making something rarely used have the same weight as the general case. That's how you got cruft in the first place.

The problem is that you don't define "the general case". Of course, it'd be better to have something aesthetically more pleasing (did we mention (FUNCALL (compose 'sin 'cos) 42)?) but this is really, really small stuff.

> mapcar is an aberration and map taking as a stupid first argument a symbol saying what type of collection the mapping should generate is laughable. Wouldn't it be better if map was simply usable over sequences all the same?

And what should be the type of sequence returned? Answer this question and you are back to the AS-VECTOR (AS-LIST, AS-STRING) issue?

> besides, are you really complaining about an extra pair of Lisp's parentheses there as accounting for "complexity"?

Nope. I am not complaining about anything, apart from what I personally (that's just me) perceive as RPs ("real problems").

>
> > You have made "I want it simpler than simple" remarks in the past if memory serves me well. I don't find them particularly compelling, especially because they usually fall short of considering all the ramifications of the simplification you propose.
>
> go read the complains about CL WJ posted below. Though I'm sure its old news to you and wont change your taste for that koolaid...

It is all well know stuff by respected people. Alas, unless you *really* change the rules of the game (i.e., you move to something like Haskell (*)) the replacements for CL (or Scheme/Racket) are lacking.


> *edit* oh, you did already...
>
> > > get rid of cruft. and the weight behind a name.
> >
> > Define "cruft".
>
> all that jazz from now deceased lisps that one way or the other had to go into CL.

FEXPRs is jazz that the CL crowd decided not to play anymore.

Cheers
--
MA

(*) It has been said here on C.L.L. that even Haskell is "not quite modern" because it had to "incorporate old typing stuff" (more or less: I paraphrase, but I don't think to be much off-target). The comment was made in conjunction with the celebration of the "modernity" of F#. You can guess who wrote such thing.

Chiron

unread,
Mar 8, 2012, 12:00:59 PM3/8/12
to
On Thu, 08 Mar 2012 16:34:37 +0100, Pascal J. Bourguignon wrote:

> Chiron <chiron613.no.spam.@no.spam.please.gmail.com> writes:
>
>> The biggest difference between time and space is that you can't reuse
>> time.
>> -- Merrick Furst
>
> Clearly wrong.
>
> If you take two people and put them in different space, you can have
> them do two things at the same time. That's a clear instance of time
> reuse.
>
> On the contrary, you can hardly put two different persons in the same
> space: there's no reuse of space, at least for fermion-like persons.


OK, sure, whatever. That was a fortune. My newsreader adds a random
fortune to my sig. Most of the fortunes are intended to be humorous.

But you're talking about two simultaneous instances (two different people
doing something, versus the inability of two people to occupy the same
space *simultaneously*). Where did this come from? Doing two things at
the same time isn't reusing the time; it is only using it.

What you can do is to put something into your attic on Tuesday. Then
remove it and put something into the attic on Wednesday - you have reused
the space. However, you cannot then put anything anywhere on the Tuesday
that has already elapsed.

--
But what can you do with it? -- ubiquitous cry from Linux-user partner.
(Submitted by Andy Pearce, a...@hpopd.pwd.hp.com)

Alex Mizrahi

unread,
Mar 8, 2012, 12:38:04 PM3/8/12
to
>> Other ways to do it:
>> * tail recursion with accumulator -- "not intuitive", might be cumbersome
>> * imperative code with non-local transfer of control and imperative
>> aggregation (e.g. incf) -- more verbose, cumbersome, harder to read
>> * multiple map passes over temporary lists -- inefficient in non-lazy
>> languages, cannot work with side effects
>
> Not that I intend or care to prove anything, but here is an
> alternative implementation which I guess fits into the "tail recursion
> with accumulator" type of solution:

Yes.

> (labels ((dowork (count&aux (line (read stream nil)))
> (when (and line (plusp count))
> ;; do block
> (work (1- count)))))
> (dowork 10))

> Isn't Clojure using similar approaches precisely because it lacks a
> loop-like macro in order to be more "functional"?

Yes. Example from manual:

(def factorial
(fn [n]
(loop [cnt n acc 1]
(if (zero? cnt)
acc
(recur (dec cnt) (* acc cnt))))))

Looks very intuitive, doesn't it? Clearly Clojure is a modern language.

> I would argue that if programmers would start out with Scheme instead of
> some C-like language then they would find the loop version less
> intuitive.

Usually by intuitive people mean that knowledge and skills obtained in a
different field can be reused. (But often people miss that there should
be some knowledge and skill in the first place, so it's relative.)

It is true that knowledge of C might help to understand Lisp's LOOP.

However, I think knowledge of plain English language and math helps with
Lisp's LOOP too. namekuseijin intentionally didn't even try to
understand it, but if one reads it as plain English:

Loop, repeat 10 [times]:
for count upfrom 1,
for line read from stream,
while [we have] line
do ...

It isn't that hard to figure out what is going on.
So it tries to read line, repeating it 10 times. So you want to read 10
lines, got it. But what if line can't be read? We stop due to `while`.
And count is used to count lines.
Makes sense, no?

OTOH your version is very cryptic for people who are not familiar with
programming languages which have this syntax. So it isn't intuitive in
sense that it is hard to re-use background knowledge of English and math.

But sure, if you learn Scheme you'll find Haskell easier and vice versa.
So one can say that parts of Haskell is intuitive to Scheme user.

Another problem with looping-with-tail-recursion, as demonstrated by
this example, is that it shuffles aspects of iteration about, and so it
might be hard to pick one aspect just looking at code: you have to read
it all, analyze it, and only then you understand.

With LOOP you can easily tell that it is executed at most 10 times.
There was another way to write it:
for count from 1 to 10
which is also obvious.

But with recursive version, let's start with a call order:

(dowork 10)

10 what? Times? Have no idea, let's read further:

(count &aux (line (read stream nil)

Ok, so 10 was count. Does it count to 1 or to 0? Let's read further:

(when (and line (plusp count))

Oh, so (plusp count) means that code is executed only if count is
positive, thus count = 1 is the last time it is executed, hence count =
10..1, it is executed 10 times at most.

So we had to go through three lines of code just to see number of
iterations. And if you want to verify that code is correct you also need
to check line with (1- count), so iteration counter is spread over four
lines of code. This is why I would call it cumbersome.

BTW note that you code produces different result from Teemu's loop: it
counts from 10 to 1, which probably isn't right. To make it counting in
the right direction we need to change three lines of code:

(labels ((dowork (count &aux (line (read stream nil)))
(when (and line (<= count 10))
;; do block
(work (1+ count)))))
(dowork 1))

While with LOOP you only need to change upfrom to downfrom and 1 to 10.

From my experience with writing Haskell code, it isn't just a bad lack
but more like a general pattern: it's hard to tell what function does
without reading all of it.

I think WJ subconsciously understands it: he calls LOOP version "low"
because it requires lower amount of mental effort to write and
understand, and functional version "high" because it requires higher amount.
For some reason he thinks that higher is better here, perhaps he is a
fan of solving puzzles.

namekuseijin

unread,
Mar 8, 2012, 12:58:56 PM3/8/12
to
On Thursday, March 8, 2012 7:06:23 AM UTC-3, Pascal J. Bourguignon wrote:
> namekuseijin <nameku...@gmail.com> writes:
>
> > we hang on comp.lang.lisp because we think Lisp is worthwhile without
> > all the cruft from ages past. We just don't like the CL zombie.
>
> (defpackage "MODERN-LISP"
> (:use "CL")
> (:export "FIRST" ; not "CAR"
> "REST" ; not "CDR"
> "SETF"
> …))
>
> (defpackage "MY-PROGRAM"
> (:use "MODERN-LISP"))
> (in-package "MY-PROGRAM")
>
> (first '(1 2 3))

I'm using Racket, which is a batteries-included Scheme and more. Previously I used my own implementations in R5RS of such common and useful functions and idioms.

Leandro Rios

unread,
Mar 8, 2012, 1:23:47 PM3/8/12
to
El 08/03/12 14:58, namekuseijin escribió:
Are you aware that he's pulling your leg?

Leandro

namekuseijin

unread,
Mar 8, 2012, 2:41:51 PM3/8/12
to
On Thursday, March 8, 2012 4:08:25 AM UTC-3, Chiron wrote:
> So, then, is your objection to CL specifically, but you're OK with some
> other (perhaps not yet implemented) version of lisp? Is there even such
> a version? What you describe sounds less like a dialect of lisp, and
> more like an entirely different language. I wonder where the boundaries
> are...

Scheme, Qi, Clojure and newLisp are all dialects of Lisp with far less cruft.

> Ah, well. Boa noite.

boa tarde.

Chiron

unread,
Mar 8, 2012, 2:51:34 PM3/8/12
to
On Thu, 08 Mar 2012 11:41:51 -0800, namekuseijin wrote:

> Scheme, Qi, Clojure and newLisp are all dialects of Lisp with far less
> cruft.

Hmm... I've just been learning lisp - CL, apparently. Now I'm wondering
whether it would be more in my interest to focus on something else - or
whether it's better to have a foundation in CL before trying those
others. I wonder whether I'd be learning the bad habits of CL that I'd
have to just unlearn with one of those dialects.

My interest, fortunately, is totally non-professional, so I can afford to
waste time.

--
The honeymoon is not actually over until we cease to stifle our sighs
and begin to stifle our yawns.
-- Helen Rowland

Teemu Likonen

unread,
Mar 8, 2012, 3:15:09 PM3/8/12
to
Maybe so, but what is the point of this discussion? If the point is
"Common Lisp needs fixing" then just do it. It's trivial to create your
non-cruft Common Lisp.

(shadow "CRUFT")
(defun modern-stuff ...)

Then publish your modern language and have it in the Quicklisp
repository so everybody can benefit from this better language.

Tim Bradshaw

unread,
Mar 8, 2012, 3:46:20 PM3/8/12
to
Chiron <chiron613.no.spam.@no.spam.please.gmail.com> wrote:

> Hmm... I've just been learning lisp - CL, apparently. Now I'm wondering
> whether it would be more in my interest to focus on something else - or
> whether it's better to have a foundation in CL before trying those
> others. I wonder whether I'd be learning the bad habits of CL that I'd
> have to just unlearn with one of those dialects.

It is obviously entirely up to you which you learn (and just to be clear: I
care whether CL is popular in the same way I care whether Lie groups are
popular). However I would suggest that you might want to think about what
is motivating the couple of people who spend, clearly, quite a lot of time
in CLL being relentlessly negative about CL. I don't pretend to understand
their motivations, but it does seem to me at least a bit odd and unhealthy
that a person who doesn't like something would spend quite so much time
exposing themselves to it when it would be very easy to avoid it entirely
(I don't personally like modern motorsports, and you will probably not be
surprised to learn that I therefore don't hang out in fora modern
motorsports are discussed (and this despite there being a Formula 1 car
sitting 20 yards from my desk).

Leandro Rios

unread,
Mar 8, 2012, 4:35:30 PM3/8/12
to
El 08/03/12 16:51, Chiron escribió:
> On Thu, 08 Mar 2012 11:41:51 -0800, namekuseijin wrote:
>
>> Scheme, Qi, Clojure and newLisp are all dialects of Lisp with far less
>> cruft.
>
> Hmm... I've just been learning lisp - CL, apparently. Now I'm wondering
> whether it would be more in my interest to focus on something else - or
> whether it's better to have a foundation in CL before trying those
> others. I wonder whether I'd be learning the bad habits of CL that I'd
> have to just unlearn with one of those dialects.
>
> My interest, fortunately, is totally non-professional, so I can afford to
> waste time.
>

Any Lisp will be ok to learn the fundamentals. However, if you want to
learn about classical tail and mutual recursion, avoid Clojure. If you
want to learn to program in a lexically scoped Lisp, avoid NewLISP. Qi
is a functional language related to lisp, and in fact runs on top of CL,
so I don't know how it is free from its "cruft" (whatever that means).
Pick Scheme or CL and keep learning. For an enlightening exercise in the
differences between Scheme and CL (Lisp1 vs Lisp2), read SICP and solve
its problems in CL.

Have fun!

Leandro

PS: There is no such thing as "bad habits of CL" :)

namekuseijin

unread,
Mar 8, 2012, 4:48:09 PM3/8/12
to
I don't think so. You'll be just adding more cruft to your giant spaghetti ball (besides shadow) and your new language is written in old cruft.

ok, I guess by now everyone is pretty sick of all the cruft...

Lisp needs to be reworked with craft. Fortunately, it is outside CL.

Chiron

unread,
Mar 8, 2012, 5:10:12 PM3/8/12
to
On Thu, 08 Mar 2012 18:35:30 -0300, Leandro Rios wrote:

Leandro, thanks for the advice. Barring any urgent warnings, I had
planned to stick with CL since I've already begun, and have bought a book
or two about it. Also it's on my computer already. I'll check Scheme,
which is also on my computer. I have never even heard of Qi as a
programming language.

Your suggestion about SICP is also quite helpful. This should keep me
busy for a while, I'd say...

> Have fun!

That was the plan. Again, thanks.

Oh, yeah. I'm glad there aren't bad habits in CL - though I suppose
that's not a wholly objective statement. I was kind of thinking of
Dijkstra's comment that BASIC ruined students, making them unable to
learn how to program...

--
How much net work could a network work, if a network could net work?

Chiron

unread,
Mar 8, 2012, 5:15:20 PM3/8/12
to
I've kind of wondered myself about how so often people who don't like
something, hang around NG's to tell everyone how much they don't like
it. I guess they just like to rattle peoples' cages. CLL is nothing
compared to comp.os.linux.advocacy, for example. Troll heaven.

My plan is to stick with CL, check out Scheme, and then maybe even Qi -
which is a complete unknown to me. That ought to keep me busy.

Alas, I don't think that Lie groups are ever going to be real popular. I
mean, mention them at a party and you might as well have told everyone
you've got worms, for all the good it will do you socially.

--
If all the world's a stage, I want to operate the trap door.
-- Paul Beatty

namekuseijin

unread,
Mar 8, 2012, 5:38:54 PM3/8/12
to
On Thursday, March 8, 2012 7:10:12 PM UTC-3, Chiron wrote:
> Oh, yeah. I'm glad there aren't bad habits in CL - though I suppose
> that's not a wholly objective statement.

aside from the thick layers of smelly historical cruft and the whole lisp-2 slotty nature, there's not much bad habits indeed. At least it's lisp.

Kaz Kylheku

unread,
Mar 8, 2012, 10:47:16 PM3/8/12
to
On 2012-03-08, Pascal J. Bourguignon <p...@informatimago.com> wrote:
> Chiron <chiron613.no.spam.@no.spam.please.gmail.com> writes:
>
>> The biggest difference between time and space is that you can't reuse
>> time.
>> -- Merrick Furst
>
> Clearly wrong.
>
> If you take two people and put them in different space, you can have
> them do two things at the same time. That's a clear instance of time
> reuse.
>
> On the contrary, you can hardly put two different persons in the same
> space: there's no reuse of space, at least for fermion-like persons.

You can reuse the same instance of space serially, and the same instance
of time concurrently. (Different instances of space are not space reuse,
and different instances of time are not time reuse.)

Alex Mizrahi

unread,
Mar 9, 2012, 3:21:38 AM3/9/12
to
> The irony is that LOOP does the job it is supposed to do so well that
> even tough I have tried various alternatives (eg iterate and doplus),
> I still end up using LOOP.

Well, yeah. It is a bad case of "worse is better" -- LOOP is ugly in
many aspects, but it kinda works and is readily available.
There is a pressure to use LOOP:
* unnecessary dependencies are frowned upon
* other people might have problems understanding your code if
it uses some other library
* if you get used to a library which is different from LOOP you'll
less efficient with understanding and writing LOOP code where it is
necessary

So we are stuck with LOOP same way we're stuck with POSIX.
But conservative, compatible extensions to LOOP might work -- it would
leave only dependency problem.

Teemu Likonen

unread,
Mar 9, 2012, 4:21:03 AM3/9/12
to
* Alex Mizrahi [2012-03-09 10:21:38 +0200] wrote:

> Well, yeah. It is a bad case of "worse is better" -- LOOP is ugly in
> many aspects, but it kinda works and is readily available.

I agree that LOOP has its ugly parts but disagree with "it kinda works".
It _really_ works. It's makes many complex iterations really easy to
write and read.

Pascal J. Bourguignon

unread,
Mar 9, 2012, 5:02:40 AM3/9/12
to
No, I'm dead serrious. You don't have to wait for racket developers to
design the language you like. With Common Lisp, you can make it
yourself. Just define a package exporting the operators you want in
your language and godspeed!

Jussi Piitulainen

unread,
Mar 9, 2012, 5:12:04 AM3/9/12
to
Pascal J. Bourguignon writes:

> No, I'm dead serrious. You don't have to wait for racket developers
> to design the language you like. With Common Lisp, you can make it
> yourself. Just define a package exporting the operators you want in
> your language and godspeed!

Racket should be excellent for that. I haven't followed it, but it
used to be a strong point with DrScheme and I'm sure it still is after
they changed the name.

Antsan

unread,
Mar 9, 2012, 5:35:22 AM3/9/12
to
Maybe they're here because CL isn't the only Lisp that could be discussed on comp.lang.lisp (which is not comp.lang.common-lisp)?

Not that I like trolling and flaming, but people who don't like CL still can like any other dialect of Lisp.

Alex Mizrahi

unread,
Mar 9, 2012, 6:49:06 AM3/9/12
to
> Alas, I don't think that Lie groups are ever going to be real popular. I
> mean, mention them at a party and you might as well have told everyone
> you've got worms, for all the good it will do you socially.

FWIW my friends once recorded a song reading "lyrics" from some advanced
math book. It mentioned Lie algrebras IIRC.


WJ

unread,
Mar 9, 2012, 8:57:57 AM3/9/12
to
WJ wrote:

>
> In PCL, there is a chapter promoting the use of the COBOL-like
> LOOP. I think that the examples can be done more elegantly
> without LOOP by using NewLisp.
>
>
>
> The low, loopy way:
>
> (loop for i upto 10 collect i)
>
>
> The high way:
>
> (sequence 0 10)
>
>
>
>
>
> The low, loopy way:
>
> (loop repeat 5
> for x = 0 then y
> for y = 1 then (+ x y)
> collect y)
> ==> (1 2 4 8 16)
>
>
> The high way:
>
> (map (curry pow 2) (sequence 0 4))
> ==> (1 2 4 8 16)
>
> Another way:
>
> (series 1 2 5)
> ==> (1 2 4 8 16)
>
>
>
>
> The low, loopy way:
>
> (loop for (a nil) in '((1 2) (3 4) (5 6)) collect a)
> ==> (1 3 5)
>
>
> The high way:
>
> (map first '((1 2) (3 4) (5 6)))
> ==> (1 3 5)
>
>
>
>
>
> The low, loopy way:
>
> (loop for (a b) in '((1 2) (3 4) (5 6))
> do (format t "a: ~a; b: ~a~%" a b))
>
> ==>
> a: 1; b: 2
> a: 3; b: 4
> a: 5; b: 6
>
>
> The high way:
>
> (dolist (x '((1 2) (3 4) (5 6)))
> (println (format "a: %d; b: %d" x)))
>
> ==>
> a: 1; b: 2
> a: 3; b: 4
> a: 5; b: 6
>
>
>
>
>
>
>
> The low, loopy way:
>
> (loop for (item . rest) on '(0 1 2 3 4 5 6 7 8)
> do (format t "~a" item)
> when rest do (format t ", "))
>
> ==>
> 0, 1, 2, 3, 4, 5, 6, 7, 8
>
>
> The high way:
>
> (print (join (map string (sequence 0 8)) ", "))
>
> ==>
> 0, 1, 2, 3, 4, 5, 6, 7, 8
>
>
>
>
> The low, loopy way:
>
> (defparameter random (loop repeat 100 collect (random 10000)))
>
> (loop for i in random
> counting (evenp i) into evens
> counting (oddp i) into odds
> summing i into total
> maximizing i into max
> minimizing i into min
> finally (return (list min max total evens odds)))
>
> ==>
> (47 9964 543718 46 54)
>
>
> The high way:
>
> (setq random (rand 10000 100))
>
> (append
> (map (fn (f) (apply f random)) (list min max +))
> (map (fn (f) (length (filter f random))) (list even? odd?)))
>
> ==>
> (87 9996 522987 49 51)
>
>
>
> Here are the definitions of odd? and even?:
>
> (define (odd? n) (= 1 (% n 2)))
> (define (even? n) (not (odd? n)))

While we're at it, let's do it in PicoLisp.


In PCL, there is a chapter promoting the use of the COBOL-like
LOOP. I think that the examples can be done more elegantly
without LOOP by using PicoLisp.



The low, loopy way:

(loop for i upto 10 collect i)


The high way:

(range 0 10)





The low, loopy way:

(loop repeat 5
for x = 0 then y
for y = 1 then (+ x y)
collect y)
==> (1 2 4 8 16)


The high way:

(mapcar '((n) (** 2 n)) (range 0 4))
==> (1 2 4 8 16)





The low, loopy way:

(loop for (a nil) in '((1 2) (3 4) (5 6)) collect a)
==> (1 3 5)


The high way:

(mapcar car '((1 2) (3 4) (5 6)))
==> (1 3 5)





The low, loopy way:

(loop for (a b) in '((1 2) (3 4) (5 6))
do (format t "a: ~a; b: ~a~%" a b))

==>
a: 1; b: 2
a: 3; b: 4
a: 5; b: 6


The high way:

(for x '((1 2) (3 4) (5 6))
(prinl (apply text x "a: @1; b: @2")))

==>
a: 1; b: 2
a: 3; b: 4
a: 5; b: 6




The low, loopy way:

(loop for (item . rest) on '(0 1 2 3 4 5 6 7 8)
do (format t "~a" item)
when rest do (format t ", "))

==>
0, 1, 2, 3, 4, 5, 6, 7, 8


The high way:

(prinl (glue ", " (range 0 8)))

==>
0, 1, 2, 3, 4, 5, 6, 7, 8




The low, loopy way:

(defparameter *random* (loop repeat 100 collect (random 10000)))

(loop for i in *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))

==>
(47 9964 543718 46 54)


The high way:

(setq *random* (mapcar '(_ (rand 0 9999)) (need 100)))

(append
(mapcar '((f) (apply f *random*)) '(min max +))
(mapcar '((f) (cnt f *random*)) '(even? odd?)))

==>
(39 9927 521863 51 49)



Here are the definitions of odd? and even?:

(de odd? (n) (bit? 1 n))
(de even? (n) (not (odd? n)))

Tim Bradshaw

unread,
Mar 9, 2012, 9:26:21 AM3/9/12
to
Antsan <thomas.b...@googlemail.com> wrote:

> Maybe they're here because CL isn't the only Lisp that could be discussed
> on comp.lang.lisp (which is not comp.lang.common-lisp)?
>
> Not that I like trolling and flaming, but people who don't like CL still
> can like any other dialect of Lisp.

Of course they can, and if they ever said anything actually useful and
constructive instead of this endless, and really boring, whining that would
be just fine by me. But they don't because they don't want things to be
better, of course.

Tim Bradshaw

unread,
Mar 9, 2012, 9:26:25 AM3/9/12
to
Jussi Piitulainen <jpii...@ling.helsinki.fi> wrote:

> Racket should be excellent for that. I haven't followed it, but it
> used to be a strong point with DrScheme and I'm sure it still is after
> they changed the name.

With surprisingly few restrictions any lisp-family language lets you do
this pretty easily: certainly both CL and Racket/DrScheme are fine for
this, and i've built variant languages in both. Of course the people who
like complaining so much might not want things to be fixed.

Jussi Piitulainen

unread,
Mar 9, 2012, 9:54:00 AM3/9/12
to
Tim Bradshaw writes:
Indeed. Much of Lisp-family programming can be seen as extending the
language or implementing languages. It's just routine.

I believe DrScheme went (Racket goes?) quite far in its support of
variant language implementation, having it as part of its built-in
pedagogical approach. I seem to remember that there is special support
for re-defining the meaning of procedure calls, of all things.

CL has its programmable reader, so even the lexical syntax can be
changed in a standard way.

(But I hope I haven't said anything truly controversial. No time for
such.)

Tim Bradshaw

unread,
Mar 9, 2012, 10:17:39 AM3/9/12
to
Jussi Piitulainen <jpii...@ling.helsinki.fi> wrote:
> Tim Bradshaw writes:

> I believe DrScheme went (Racket goes?) quite far in its support of
> variant language implementation, having it as part of its built-in
> pedagogical approach. I seem to remember that there is special support
> for re-defining the meaning of procedure calls, of all things.
>

Yes, they have lots of variants: lazy versions, typed versions and so on.

Marco Antoniotti

unread,
Mar 9, 2012, 12:05:01 PM3/9/12
to
I second that!

--
MA

Raymond Wiker

unread,
Mar 9, 2012, 1:29:04 PM3/9/12
to
Kate Bush has a song named "Pi". No prize for guessing what
*that* is about.

Raymond Wiker

unread,
Mar 9, 2012, 1:31:08 PM3/9/12
to
What a master of rational discourse you are.

Alex Mizrahi

unread,
Mar 9, 2012, 1:55:52 PM3/9/12
to
Do I understand it correctly that "low way" means that low amount of
mental effort is requires to write or read code, while "high way" means
that it requires high amount of effort, concentration, etc.?

Marco Antoniotti

unread,
Mar 9, 2012, 2:09:26 PM3/9/12
to
I was trying to formulate that very same question about WJ's Newspeak, but fell asleep in the process....

Cheers
--
MA

Chiron

unread,
Mar 9, 2012, 2:20:41 PM3/9/12
to
On Fri, 09 Mar 2012 19:29:04 +0100, Raymond Wiker wrote:

> Kate Bush has a song named "Pi". No prize for guessing what
> *that* is about.

The song's OK, I guess, but she didn't finish it...

--
If God hadn't wanted you to be paranoid, He wouldn't have given you such
a vivid imagination.

Chiron

unread,
Mar 9, 2012, 2:29:06 PM3/9/12
to
On Thu, 08 Mar 2012 14:38:54 -0800, namekuseijin wrote:

> aside from the thick layers of smelly historical cruft and the whole
> lisp-2 slotty nature, there's not much bad habits indeed. At least it's
> lisp.

I think it would be more helpful if you could specify exactly what you
mean by "cruft," since the term is vague at best. So far, as a rank
noobie, CL looks pretty good to me. Perhaps you could enlighten me as to
the crufty parts.

Also, I don't understand what you mean by "slotty" behavior - is that a
term of art, or a misspelling, or what? The only "definition" I could
find for slotty was a conflation of "slutty" and "hottie." I don't see
how this could apply to your comment.

--
I use not only all the brains I have, but all those I can borrow as well.
-- Woodrow Wilson

Kaz Kylheku

unread,
Mar 9, 2012, 4:55:06 PM3/9/12
to
On 2012-03-09, Alex Mizrahi <alex.m...@gmail.com> wrote:
>> The irony is that LOOP does the job it is supposed to do so well that
>> even tough I have tried various alternatives (eg iterate and doplus),
>> I still end up using LOOP.
>
> Well, yeah. It is a bad case of "worse is better" -- LOOP is ugly in
> many aspects, but it kinda works and is readily available.

I only don't like one: how the keywords like "for" are handled like strings, so
they can be in any package. That's a hack that isn't used anywhere else and is
basically an alien concept to how symbols work.

Pascal J. Bourguignon

unread,
Mar 9, 2012, 5:26:03 PM3/9/12
to
I guess the standardization comitee didn't like to export symbols from
the COMMON-LISP package that had absolutely no binding.

They could have specified to use just keywords (which is what I do in my
program sources), but I guess they didn't want to be so directif.

RG

unread,
Mar 9, 2012, 5:35:45 PM3/9/12
to
In article <201203091...@kylheku.com>,
LOOP keywords are just that: keywords, that is, objects whose name is
their only property. They derive their semantics from the fact that
they are within the lexical scope of the LOOP macro. Because LOOP is
not extensible there is no possibility of naming conflicts. The only
reason it seems like a hack is that CL's native keywords have a horribly
clunky syntax, so if you want keywords that don't start with a colon you
have no choice but to resort to some extra-linguistic mechanism.
Whether that's a "hack" or an elegant workaround for a defect in the
language is a matter of opinion.

rg

Kaz Kylheku

unread,
Mar 9, 2012, 6:18:44 PM3/9/12
to
On 2012-03-09, RG <rNOS...@flownet.com> wrote:
> In article <201203091...@kylheku.com>,
> Kaz Kylheku <k...@kylheku.com> wrote:
>
>> On 2012-03-09, Alex Mizrahi <alex.m...@gmail.com> wrote:
>> >> The irony is that LOOP does the job it is supposed to do so well that
>> >> even tough I have tried various alternatives (eg iterate and doplus),
>> >> I still end up using LOOP.
>> >
>> > Well, yeah. It is a bad case of "worse is better" -- LOOP is ugly in
>> > many aspects, but it kinda works and is readily available.
>>
>> I only don't like one: how the keywords like "for" are handled like strings,
>> so
>> they can be in any package. That's a hack that isn't used anywhere else and
>> is
>> basically an alien concept to how symbols work.
>
> LOOP keywords are just that: keywords, that is, objects whose name is
> their only property. They derive their semantics from the fact that
> they are within the lexical scope of the LOOP macro. Because LOOP is

It seems you have a technical disagreement with Pascal who wrote, in a sibling
article:

P> I guess the standardization comitee didn't like to export symbols from
P> the COMMON-LISP package that had absolutely no binding.

If the loop keywords are lexically scoped, that makes them bindings of some kind.

> not extensible there is no possibility of naming conflicts.

LOOP is not extensible /today/. A dumb hack like that ensures that
if it becomes extensible in the future, it will have issues.

> The only
> reason it seems like a hack is that CL's native keywords have a horribly
> clunky syntax, so if you want keywords that don't start with a colon you

You cannot add less than a character to an identifier to mark it as a keyword.

So by "clunky", you must mean that identifier tokens require any additional
syntax whatsoever to be keywords.

But for keyword tokens to be "non clunky" (identifiers with zero characters of
additional syntax) maybe other things in the language would become clunky,
possibly such that the overall clunkiness increases.

> if you want keywords that don't start with a colon you
> have no choice but to resort to some extra-linguistic mechanism.

If you're sitting on a committee standarizing Common Lisp and you suddenly want
keywords without a colon, just for the sake of some macro, you should leave the
building immediately and go work on something else.

Since those keywords are in fact lexically scoped --- they are bindings to meaning
within the scope of a loop --- they should be exported symbols from COMMON-LISP,
like COMMON-LISP::LOOP itself.

Say, (return foo) is only meaningful when lexically scoped within a block. Why
isn't return also string-matched then so you can use (mypackage::return)
or even ("RETURN" foo)?

RG

unread,
Mar 10, 2012, 1:23:53 PM3/10/12
to
In article <201203091...@kylheku.com>,
Kaz Kylheku <k...@kylheku.com> wrote:

> > LOOP keywords are just that: keywords, that is, objects whose name is
> > their only property. They derive their semantics from the fact that
> > they are within the lexical scope of the LOOP macro. Because LOOP is
>
> It seems you have a technical disagreement with Pascal who wrote, in a
> sibling
> article:
>
> P> I guess the standardization comitee didn't like to export symbols from
> P> the COMMON-LISP package that had absolutely no binding.
>
> If the loop keywords are lexically scoped, that makes them bindings of some
> kind.

Sort of.

First of all, neither keywords nor symbols *are* bindings. Bindings are
not first-class in CL. Keywords and symbols are. Keywords and symbols
HAVE bindings, or "have bindings associated with them" if you prefer.
But it is never correct to say that a keyword or symbol IS a binding, or
that something MAKES IT a binding.

Second, there is more than one kind of lexical binding. There are
lexical variable bindings. This is by far the most common kind of
lexical binding. It is the sort of lexical binding established by
LAMBDA, LET, LET*, MULTIPLE-VALUE-BIND, WITH-OPEN-FILE, etc. etc. (I
know you know this. I'm being precise for the benefit of lurkers
because the idea of LOOP keywords being a lexical binding is a pretty
subtle concept.)

But there are other kinds of lexical bindings. For example, there are
lexical function bindings of the sort established by FLET and LABELS.
There are lexical block bindings of the sort established by TAGBODY and
BLOCK.

The kind of lexical bindings established by the LOOP macro are unique to
LOOP in two respects. First, the semantics of those bindings are unique
to LOOP. There is nothing like the semantics of, say, "INTO" anywhere
else in CL. And second, and more to the point for this discussion,
those bindings are anaphoric, that is, the thing being bound is not
specified by the user, it is implicit in the definition of the LOOP
macro.

So yes, LOOP keywords have bindings, but they are a very particular sort
of binding, a kind of binding that exists only within a LOOP macro, and
which is not usually considered a binding in common parlance (despite
the fact that it is in fact a kind of binding). So what Pascal said is
not far from the truth.

> > not extensible there is no possibility of naming conflicts.
>
> LOOP is not extensible /today/. A dumb hack like that ensures that
> if it becomes extensible in the future, it will have issues.

LOOP, like everything else in Common Lisp (by which I mean those parts
of the language described in the ANSI spec), will never change. The CL
community is far too politically dysfunctional for that.

Bet let us suspend disbelief for a moment and imagine that politics is
not an insurmountable hurdle. How exactly would you propose to allow
LOOP to become extensible? LOOP is not really Lisp, it is a DSL
embedded within Lisp (this is the reason it's so polarizing) and it is
not designed to be extended. So how would you do it?

(Feel free to treat that as rhetorical question.)

> > The only
> > reason it seems like a hack is that CL's native keywords have a horribly
> > clunky syntax, so if you want keywords that don't start with a colon you
>
> You cannot add less than a character to an identifier to mark it as a
> keyword.

Not sure what you mean here. Characters are atomic units. You cannot
add less than one of them to anything because the only quantity less
than one would be zero.

But I presume you meant to write something like: you cannot be bothered
to add even a single character to mark a lexical entity as a keyword?

i.e. you would prefer that people be required to write:

(loop :for x :in '(1 2 3) :collect ...)

or maybe:

(loop #:for x #:in '(1 2 3) #:collect ...)

The cost of that extra syntax is not just the cost of typing in #:all
#:that #:extra #:punctuation. #:It #:is #:also #:the #:cognitive
#:burden #:that #:is #:imposed #:on #:anyone #:who #:tries #:to #:read
#:the #:resulting #:code. It's not the typing that's the problem, it's
all the extra (and unnecessary) thinking that's required to do the extra
typing in the right places and nowhere else. The whole point of
high-level languages is to make it easier for people to write programs.
And people think in keywords, not symbols.

Maybe that's the fundamental issue here. Lisp arose from AI, and in
particular, the hypothesis that intelligence is a symbol-manipulation
process. But intelligence is (almost certainly) NOT a
symbol-manipulation process. The words you are reading right now are
not symbols, they are keywords. They are indexes into some kind of data
structure in your brain that we do not yet fully understand. But their
semantics are NOT determined by the setting of some global setting of
*package* (or *langauge*) in your brain, que se demuestra fácilmente por
cambiando las lenguas en el medio de una frase ohne explizit
signalisieren eine Änderung im Zusammenhang.

The genius of symbols and S-expressions is the recognition that human
brains do not parse character strings directly into operational
semantics, and so you win big if your language has a first-class
intermediate representation that you can manipulate computationally (the
parse tree). The problem is that there are (at least) TWO levels of
indirection in the human brain, not just one. Human babies who
eventually become, say, speakers of English learn that the serial
concatenation of the phonemes "M" "AH" "M" "EE" is a semantically
meaningful atomic unit (i.e. a keyword) long before they learn what
those semantics actually are, or that the keyword can be rendered
visually as well as aurally.

> So by "clunky", you must mean that identifier tokens require any additional
> syntax whatsoever to be keywords.

Yes.

> But for keyword tokens to be "non clunky" (identifiers with zero characters
> of
> additional syntax) maybe other things in the language would become clunky,
> possibly such that the overall clunkiness increases.

Only if you do it wrong. It is a pretty minor tweak to CL's current
design to have the best of both worlds. All you need to do is to add a
level of indirection. Instead of:

string->(reader)->symbol

do:

string->(reader)->keyword->(lexicon)->symbol (or whatever)

That way one can even reclaim the colon as a constituent character.

> > if you want keywords that don't start with a colon you
> > have no choice but to resort to some extra-linguistic mechanism.
>
> If you're sitting on a committee standarizing Common Lisp and you suddenly
> want
> keywords without a colon, just for the sake of some macro, you should leave
> the
> building immediately and go work on something else.
>
> Since those keywords are in fact lexically scoped --- they are bindings to
> meaning
> within the scope of a loop --- they should be exported symbols from
> COMMON-LISP,
> like COMMON-LISP::LOOP itself.
>
> Say, (return foo) is only meaningful when lexically scoped within a block.
> Why
> isn't return also string-matched then so you can use (mypackage::return)
> or even ("RETURN" foo)?

Because BLOCK does not define a fully-fledged DSL the way LOOP does.

A better analogy would be FORMAT, which also defines a (very different
kind of) DSL. Imagine you wanted to make FORMAT user-extensible. How
would you do it?

rg

Lieven Marchand

unread,
Mar 10, 2012, 1:50:38 PM3/10/12
to
RG <rNOS...@flownet.com> writes:

> Bet let us suspend disbelief for a moment and imagine that politics is
> not an insurmountable hurdle. How exactly would you propose to allow
> LOOP to become extensible? LOOP is not really Lisp, it is a DSL
> embedded within Lisp (this is the reason it's so polarizing) and it is
> not designed to be extended. So how would you do it?
>
> (Feel free to treat that as rhetorical question.)

Sorry to be contrarian but LOOP was extensible from the beginning. The
whole ADD-LOOP-PATH mechanism is even today lurking in most
implementations. It just didn't make it into the ANSI specification.

Kaz Kylheku

unread,
Mar 10, 2012, 2:40:43 PM3/10/12
to
On 2012-03-10, RG <rNOS...@flownet.com> wrote:
> Second, there is more than one kind of lexical binding. There are
> lexical variable bindings. This is by far the most common kind of
> lexical binding. It is the sort of lexical binding established by
> LAMBDA, LET, LET*, MULTIPLE-VALUE-BIND, WITH-OPEN-FILE, etc. etc. (I
> know you know this. I'm being precise for the benefit of lurkers
> because the idea of LOOP keywords being a lexical binding is a pretty
> subtle concept.)

Not really. It's exactly like some (break) working within the range of a loop.
Implicit local macrolet type thing.

> But there are other kinds of lexical bindings. For example, there are
> lexical function bindings of the sort established by FLET and LABELS.
> There are lexical block bindings of the sort established by TAGBODY and
> BLOCK.
>
> The kind of lexical bindings established by the LOOP macro are unique to
> LOOP in two respects. First, the semantics of those bindings are unique
> to LOOP. There is nothing like the semantics of, say, "INTO" anywhere
> else in CL.

Sure there is, for instance:

:initarg foo

INTO is essentially just an optional keyword argument for COLLECT, not a clause
that stands by itself.

In a possible loop design, COLLECT would be CL::COLLECT, but INTO just a
keyword:

collect (* x x) :into squares

This is actually clearer.

> And second, and more to the point for this discussion,
> those bindings are anaphoric, that is, the thing being bound is not
> specified by the user, it is implicit in the definition of the LOOP
> macro.

Like (return) inside a block.

>> LOOP is not extensible /today/. A dumb hack like that ensures that
>> if it becomes extensible in the future, it will have issues.
>
> LOOP, like everything else in Common Lisp (by which I mean those parts
> of the language described in the ANSI spec), will never change. The CL
> community is far too politically dysfunctional for that.
>
> Bet let us suspend disbelief for a moment and imagine that politics is
> not an insurmountable hurdle. How exactly would you propose to allow
> LOOP to become extensible? LOOP is not really Lisp, it is a DSL
> embedded within Lisp (this is the reason it's so polarizing) and it is
> not designed to be extended. So how would you do it?

A special define mechanism for writing translators for new kinds of clauses.

The translators would be responsible for recognizing the syntax of the clause
(and hooking into the overall parse, e.g. somehow indicating to the caller how
many tokens are consumed so the parse can continue). The parsing could
be indicated by some simple phrase structure notation, or even as a lambda list.

The translators would return the list of variables they need to introduce into
the initialization of the loop, and the form introduced into every phase of
processing: what form, if any, the construct contributes to the loop prologue,
the loop body, the loop epilogue, and a default return value. For example
something like a FINALLY would contribute only to the epilogue.

;; parser interprets &rest argument as being one or more compound forms
(defloop my-finally (&rest compound-forms)
(values nil ;; no variables introduced that need bindings
nil ;; nothing for prologue
nil ;; nothing for body
`(progn ,@compound-forms) ;; epilogue
nil)) ;; no return value

(defloop my-collecting (form &key into-sym)
(let ((var (or into-sym (gensym "INTO-"))))
(values (list var) ;; one variable needed in prologue
nil ;; nothing for prologue: var is already NIL
`(setf ,var (nconc ,var (list ,form))) ;; body action
nil ;; nothing for epilogue
(unless into-sym var)))) ;; default return value

Subtleties: users shuld be able to define whether the syntax is a variable
clause (goes into for/with group), main, or can appear anywhere.

A clause like collecting needs to coordinate multiple occurences: if we write
"collecting form" in two or more places (with no into), they collect into the
same implicit list. This can be handled in various ways. It doesn't seem like
a serious difficulty.

>> > The only
>> > reason it seems like a hack is that CL's native keywords have a horribly
>> > clunky syntax, so if you want keywords that don't start with a colon you
>>
>> You cannot add less than a character to an identifier to mark it as a
>> keyword.
>
> Not sure what you mean here. Characters are atomic units. You cannot
> add less than one of them to anything because the only quantity less
> than one would be zero.
>
> But I presume you meant to write something like: you cannot be bothered
> to add even a single character to mark a lexical entity as a keyword?
>
> i.e. you would prefer that people be required to write:
>
> (loop :for x :in '(1 2 3) :collect ...)

Not necessarily. Loop without colons is okay, just put the keywords
into the CL package.

> or maybe:
>
> (loop #:for x #:in '(1 2 3) #:collect ...)
>
> The cost of that extra syntax is not just the cost of typing in #:all
> #:that #:extra #:punctuation.

Yes; "colon-free" loop is way easier to "sell" to non-Lisp programmers.

The keyword punctuation is not very helfpul in Loop because you're not
manipulating property lists or keywords.

The punctuation on keywords is quite helpful in argument or property lists,
especially long ones. It says "this is the indicator, and the thing to the
right must be the property".

One of the things I found confusing as a Lisp newbie was
:initarg :blah :initform foo in defclass. When the argument of a keyword is a
keyword, the colons no longer help. No it was before Lisp newbie time; I think
I saw that first in that OO book by Grady Booch and went "gack".

If you drop the colon, everything will be screwy like that.

A modicum of "sygils" can improve readability.

>> But for keyword tokens to be "non clunky" (identifiers with zero characters
>> of
>> additional syntax) maybe other things in the language would become clunky,
>> possibly such that the overall clunkiness increases.
>
> Only if you do it wrong. It is a pretty minor tweak to CL's current
> design to have the best of both worlds. All you need to do is to add a
> level of indirection. Instead of:
>
> string->(reader)->symbol
>
> do:
>
> string->(reader)->keyword->(lexicon)->symbol (or whatever)

So everything coming out of the reader is a keyword. I'm trying
to form a picture of how that would work.

Keywords connect remote parts of a program together so they can't be tied to
lexical scopes. Or can they?

If some function f has a keyword argument x, and we don't have special keywords
in the language, we have to pass that as 'x. To get rid of the quote, we can
use our lexicon to bind x to 'x. That is inconvenient.

But could have a rule so that if x has no binding in the enclosing stack of
lexicons, then x just evaluates to x. But what about catching uses of unbound
variables.

Maybe that's okay; it will just blow up in a different place: a symbol ends
up passed where some type of other value is expected.

(let ((misspelled 'foo)) (symbol-name misspeled)) gives
you "MISSPELED" instead of "FOO", with no help from the compiler, but
that seems minor.

Pascal J. Bourguignon

unread,
Mar 10, 2012, 3:21:10 PM3/10/12
to
Kaz Kylheku <k...@kylheku.com> writes:

> One of the things I found confusing as a Lisp newbie was
> :initarg :blah :initform foo in defclass. When the argument of a keyword is a
> keyword, the colons no longer help. No it was before Lisp newbie time; I think
> I saw that first in that OO book by Grady Booch and went "gack".
>
> If you drop the colon, everything will be screwy like that.
>
> A modicum of "sygils" can improve readability.

You can use:

:initarg ':blah :initform foo

Frank DG1SBG

unread,
Mar 10, 2012, 3:28:55 PM3/10/12
to
"Pascal J. Bourguignon" <p...@informatimago.com> writes:

> Chiron <chiron613.no.spam.@no.spam.please.gmail.com> writes:
>
>> The biggest difference between time and space is that you can't reuse
>> time.
>> -- Merrick Furst
>
> Clearly wrong.

Ah - I tend to think he's right.

> If you take two people and put them in different space, you can have
> them do two things at the same time. That's a clear instance of time
> reuse.

Reuse, in my understanding, is meant to re-use the *same* "object" - So,
re-using the *same* time is kind of not feasible. As there is no notion
of identity of a segment of time or time in general, reuse of time is
not defined.

Regards

Frank


RG

unread,
Mar 10, 2012, 3:37:37 PM3/10/12
to
In article <87sjhgi...@black.wyrd.be>,
That's not contrarian, that's (potentially) informative. I've never
heard of add-loop-path, and a Google search turns up no documentation.
But it's apparently not too obscure. SBCL and CCL both seem to have
implementations (though CLisp seems not to).

Is there a description of what add-loop-path is supposed to do somewhere?

rg

RG

unread,
Mar 10, 2012, 4:59:21 PM3/10/12
to
In article <201203101...@kylheku.com>,
Kaz Kylheku <k...@kylheku.com> wrote:

> > So how would you do it?

[lengthy description elided]

OK, I'll buy that.


> > or maybe:
> >
> > (loop #:for x #:in '(1 2 3) #:collect ...)
> >
> > The cost of that extra syntax is not just the cost of typing in #:all
> > #:that #:extra #:punctuation.
>
> Yes; "colon-free" loop is way easier to "sell" to non-Lisp programmers.

That is a significant win by my personal quality metric.

> The keyword punctuation is not very helfpul in Loop because you're not
> manipulating property lists or keywords.

Not sure what you mean by "manipulating keywords" but you're probably
right.

> The punctuation on keywords is quite helpful in argument or property lists,
> especially long ones. It says "this is the indicator, and the thing to the
> right must be the property".

Yes. But that still leaves open the question of whether or not this
helpful feature should be baked into the design of the language, or
whether it should be, for example, a programming convention like
*earmuffs*.

The Right Syntax for indicating indicators, the one that would conform
to the syntactic conventions of natural language (at least European
languages) is to put the colon at the END of the word, not the
beginning. Dylan and Objective C get this right. CL got it wrong
because it tried to shoehorn keyword syntax into the syntax of symbols,
where the natural interpretation of foo: would be 'foo::|| rather than
the desired '||::foo (or keyword::foo).

All of these issues simply evaporate if you add one level of indirection.

> One of the things I found confusing as a Lisp newbie was
> :initarg :blah :initform foo in defclass. When the argument of a keyword is
> :a
> keyword, the colons no longer help. No it was before Lisp newbie time; I
> think
> I saw that first in that OO book by Grady Booch and went "gack".
>
> If you drop the colon, everything will be screwy like that.
>
> A modicum of "sygils" can improve readability.

Agreed. But to reiterate, the issue is not whether sigils are useful,
but rather whether the syntax for them should be unalterably baked into
the specification of the language. In a "programmable programming
language" like CL I believe the design principle should be that you
ought not bake things into the language unless there's a compelling
reason.

> >> But for keyword tokens to be "non clunky" (identifiers with zero
> >> characters
> >> of
> >> additional syntax) maybe other things in the language would become clunky,
> >> possibly such that the overall clunkiness increases.
> >
> > Only if you do it wrong. It is a pretty minor tweak to CL's current
> > design to have the best of both worlds. All you need to do is to add a
> > level of indirection. Instead of:
> >
> > string->(reader)->symbol
> >
> > do:
> >
> > string->(reader)->keyword->(lexicon)->symbol (or whatever)
>
> So everything coming out of the reader is a keyword.

In a perfect world, yes.

> I'm trying to form a picture of how that would work.

http://flownet.com/ron/lisp/lexicons.pdf
http://flownet.com/ron/lisp/lexicons.lisp

> Keywords connect remote parts of a program together so they can't be tied to
> lexical scopes. Or can they?

Not sure what you mean by this. Symbol name collisions are inherently a
dynamic phenomenon.

That's one of the coolest thinks about lexical scopes: they naturally
form a hierarchical structure so that there is an obvious rule for
resolving name conflicts. Indeed it is so obvious that people don't
even THINK of lexical name conflicts as conflicts. The rule is: inner
scopes shadow outer scopes. That rule turns out to be all you need.

> If some function f has a keyword argument x, and we don't have special
> keywords
> in the language, we have to pass that as 'x. To get rid of the quote, we can
> use our lexicon to bind x to 'x. That is inconvenient.

I don't see why 'x is any more inconvenient than :x.

I completely agree that (f 'keyword value) is unaesthetic. It should be
(f keyword: value). But the way CL is currently defined, that is
necessarily a syntax error unless you muck with the reader to make #\: a
constituent, but that carries a steep price, namely, the loss of
read-print consistency.

The Right Way (IMO of course) is for #\: to be a constituent, and for
the reader to produce keywords, which should be a distinct data type
from symbols. Keywords should be (isomorphic to) immutable strings.
The names of symbols should be keywords (i.e. immutable strings), not
(mutable) strings. The leaf nodes of programs should be keywords, not
symbols. The semantics of programs made of keywords are mapped onto the
semantics of programs made of symbols by adding a pass that maps
keywords onto their corresponding bindings in the current lexicon, which
is a first class lexical environment that maps keywords onto symbols --
or possibly other things. (There are benefits from having lexicons map
keywords onto things other than symbols, but let's deal with one thing
at a time.)

(Actually, I skipped a step here. The semantics of programs made of
keywords are defined relative to a first-class global environment object
that maps keywords onto some kind of value(s). That does not
necessarily have to be a lexical environment. It can be a dynamic one.
That's what e.g. Python does. Making it a lexical environment has, I
believe, certain benefits. But the real point here is not so much that
the global environment is lexical as that it is first-class.)

> But could have a rule so that if x has no binding in the enclosing stack of
> lexicons, then x just evaluates to x. But what about catching uses of unbound
> variables.

I would handle this with reader macros. If you wanted CL-style keyword,
just define a reader macro on #\: that reads :foo as (quote foo).

You have to get a little fancier to be able to implement my preferred
syntax of foo: , but as I said, one thing at a time.

> Maybe that's okay; it will just blow up in a different place: a symbol ends
> up passed where some type of other value is expected.
>
> (let ((misspelled 'foo)) (symbol-name misspeled)) gives
> you "MISSPELED" instead of "FOO", with no help from the compiler, but
> that seems minor.

The reason you can't create lexical bindings for keywords in CL is NOT
that it would lead to naming conflicts. It's because keywords are a
special kind of symbol. They are special (no pun intended) because
every keyword is implicitly defined to be a constant bound to itself,
and you can't rebind constants.

But imagine if instead of being bound by DEFCONSTANT, keywords were
instead bound by DEFPARAMETER. Then you could do, e.g.:

(let ((:x 1)) :x) --> 1

Yes, I know, you look at that and think Blech! That would break all
kinds of things, and you're right, it would. But the one thing it would
NOT break is that it would not cause symbol naming conflicts.

So now imagine a hypothetical lisp that differs from CL in the following
respects:

1. The reader produces keywords by default
2. The names of lexical bindings are keywords, not symbols
3. There is a reader macro on #\: that reads :x as (quote x), which is
a list of two elements, both of which are keywords.
4. EVAL is just like the usual Lisp 1.5 eval, except that the ENV
argument uses keywords for keys rather than symbols. In the default
environment, the keyword QUOTE is bound to a fexpr of one argument that
returns that argument.

In such a Lisp you could write:

(let ((x 1)) (f :x x))

and it would do exactly the same thing as that code does in CL. And the
result from your example above would be "FOO" just as you expect.

Are you with me so far?

rg

RG

unread,
Mar 10, 2012, 5:15:28 PM3/10/12
to
In article <m2obs4w...@googlemail.com>,
You can't re-use time because of the definition of "re-use." You can
have different events at different locations at the same time (relative
to some inertial frame of reference of course), and you can have
different events at different times at the same location. The latter is
"re-use" and the former isn't. But that's a statement about the word
"re-use", not a statement about physics.

rg

Lieven Marchand

unread,
Mar 10, 2012, 5:27:58 PM3/10/12
to
There's two places to look at. The old Symbolics documentation (under
the name DEFINE-LOOP-PATH) and this post by Pierre Mai:

https://groups.google.com/group/comp.lang.lisp/msg/8ef3fe4f22434312?dmode=source&output=gplain&noredirect

Kaz Kylheku

unread,
Mar 10, 2012, 7:01:00 PM3/10/12
to
On 2012-03-10, RG <rNOS...@flownet.com> wrote:
> In article <201203101...@kylheku.com>,
> Kaz Kylheku <k...@kylheku.com> wrote:
>
>> > So how would you do it?
>
> [lengthy description elided]
>
> OK, I'll buy that.

Cool! I wanna be like Paul Graham; someone buys some Lisp thing I made. :)

>
>> > or maybe:
>> >
>> > (loop #:for x #:in '(1 2 3) #:collect ...)
>> >
>> > The cost of that extra syntax is not just the cost of typing in #:all
>> > #:that #:extra #:punctuation.
>>
>> Yes; "colon-free" loop is way easier to "sell" to non-Lisp programmers.
>
> That is a significant win by my personal quality metric.

Me too.

>> The keyword punctuation is not very helfpul in Loop because you're not
>> manipulating property lists or keywords.
>
> Not sure what you mean by "manipulating keywords" but you're probably
> right.

Like suppose that the data type being manipulated in loop is mostly keywords,
and all the clause words are keywords too.

(loop :for x :in '(:for :and :with)
:for y = :collecting then x
:if (eq x :and)
...)

Not sure where I'm going with this so I will stop. :)

That looks like it has the measles.

>> The punctuation on keywords is quite helpful in argument or property lists,
>> especially long ones. It says "this is the indicator, and the thing to the
>> right must be the property".
>
> Yes. But that still leaves open the question of whether or not this
> helpful feature should be baked into the design of the language, or
> whether it should be, for example, a programming convention like
> *earmuffs*.

But *earmuffs* is pretty much baked into the language.

>
> The Right Syntax for indicating indicators, the one that would conform
> to the syntactic conventions of natural language (at least European
> languages) is to put the colon at the END of the word, not the
> beginning. Dylan and Objective C get this right.

Well, objectionable C also:

repeat:
goto repeat;

:)

> because it tried to shoehorn keyword syntax into the syntax of symbols,
> where the natural interpretation of foo: would be 'foo::|| rather than
> the desired '||::foo (or keyword::foo).
>
> All of these issues simply evaporate if you add one level of indirection.
>
>> One of the things I found confusing as a Lisp newbie was
>> :initarg :blah :initform foo in defclass. When the argument of a keyword is
>> :a
>> keyword, the colons no longer help. No it was before Lisp newbie time; I
>> think
>> I saw that first in that OO book by Grady Booch and went "gack".
>>
>> If you drop the colon, everything will be screwy like that.
>>
>> A modicum of "sygils" can improve readability.
>
> Agreed. But to reiterate, the issue is not whether sigils are useful,
> but rather whether the syntax for them should be unalterably baked into
> the specification of the language. In a "programmable programming
> language" like CL I believe the design principle should be that you
> ought not bake things into the language unless there's a compelling
> reason.

A broad rule for a class of symbols that they evaluate to themselves is
pretty cool. nil and t ought to have been keywords, :nil and :t.

>> >> But for keyword tokens to be "non clunky" (identifiers with zero
>> >> characters
>> >> of
>> >> additional syntax) maybe other things in the language would become clunky,
>> >> possibly such that the overall clunkiness increases.
>> >
>> > Only if you do it wrong. It is a pretty minor tweak to CL's current
>> > design to have the best of both worlds. All you need to do is to add a
>> > level of indirection. Instead of:
>> >
>> > string->(reader)->symbol
>> >
>> > do:
>> >
>> > string->(reader)->keyword->(lexicon)->symbol (or whatever)
>>
>> So everything coming out of the reader is a keyword.
>
> In a perfect world, yes.
>
>> I'm trying to form a picture of how that would work.
>
> http://flownet.com/ron/lisp/lexicons.pdf
> http://flownet.com/ron/lisp/lexicons.lisp

Is this new in the latest version or just from old behavior?

>> Keywords connect remote parts of a program together so they can't be tied to
>> lexical scopes. Or can they?
>
> Not sure what you mean by this. Symbol name collisions are inherently a
> dynamic phenomenon.

I just mean that they are part of the expression of interfaces.

> That's one of the coolest thinks about lexical scopes: they naturally
> form a hierarchical structure so that there is an obvious rule for
> resolving name conflicts. Indeed it is so obvious that people don't
> even THINK of lexical name conflicts as conflicts. The rule is: inner
> scopes shadow outer scopes. That rule turns out to be all you need.

That rule is error-prone. That's why we have a -Wshadow gcc warning.
Good for machines though.

>> If some function f has a keyword argument x, and we don't have special
>> keywords
>> in the language, we have to pass that as 'x. To get rid of the quote, we can
>> use our lexicon to bind x to 'x. That is inconvenient.
>
> I don't see why 'x is any more inconvenient than :x.

Well, I'm now drinking the "sygil is bad" Kool-Aid for a moment. So if I throw
away :, but gain ', I have not achieved anything.

> I completely agree that (f 'keyword value) is unaesthetic. It should be
> (f keyword: value). But the way CL is currently defined, that is
> necessarily a syntax error unless you muck with the reader to make #\: a
> constituent, but that carries a steep price, namely, the loss of
> read-print consistency.

Me, I don't care if it goes to the front or back. I'm AC/DC.

> The Right Way (IMO of course) is for #\: to be a constituent, and for
> the reader to produce keywords, which should be a distinct data type
> from symbols. Keywords should be (isomorphic to) immutable strings.

Yes, so then they can be interned similarly to symbols (and used for low loopy
things).

> The names of symbols should be keywords (i.e. immutable strings), not
> (mutable) strings.

Interesting. So (name-equal x y) reduces to (eq (symbol-name x) (symbol-name y)).

> The leaf nodes of programs should be keywords, not
> symbols. The semantics of programs made of keywords are mapped onto the
> semantics of programs made of symbols by adding a pass that maps
> keywords onto their corresponding bindings in the current lexicon, which

If keywords have bindings they are symbols, which we said they are not. :)

Basically they might as well be symbols, but in a special category.

Shit, actually I had nearly the same idea several days ago. The idea
was that there should be symbols which are not in any package.

And that symbols should be separately interned in a package
and in the "no package" zone.

> is a first class lexical environment that maps keywords onto symbols --
> or possibly other things. (There are benefits from having lexicons map
> keywords onto things other than symbols, but let's deal with one thing
> at a time.)
>
> (Actually, I skipped a step here. The semantics of programs made of
> keywords are defined relative to a first-class global environment object
> that maps keywords onto some kind of value(s). That does not
> necessarily have to be a lexical environment. It can be a dynamic one.
> That's what e.g. Python does. Making it a lexical environment has, I
> believe, certain benefits. But the real point here is not so much that
> the global environment is lexical as that it is first-class.)
>
>> But could have a rule so that if x has no binding in the enclosing stack of
>> lexicons, then x just evaluates to x. But what about catching uses of unbound
>> variables.
>
> I would handle this with reader macros. If you wanted CL-style keyword,
> just define a reader macro on #\: that reads :foo as (quote foo).

But then '(:foo bar) is (quote ((quote foo) bar)). No thanks! I want :foo
to be the same thing whether it is code or data.

(This is a little bit like (define nil '()) in Scheme. It fails to
make '(nil) a list of an empty list.)

A macro that gives me a : spelling for ' is not that productive.

> You have to get a little fancier to be able to implement my preferred
> syntax of foo: , but as I said, one thing at a time.

>> Maybe that's okay; it will just blow up in a different place: a symbol ends
>> up passed where some type of other value is expected.
>>
>> (let ((misspelled 'foo)) (symbol-name misspeled)) gives
>> you "MISSPELED" instead of "FOO", with no help from the compiler, but
>> that seems minor.
>
> The reason you can't create lexical bindings for keywords in CL is NOT
> that it would lead to naming conflicts. It's because keywords are a
> special kind of symbol. They are special (no pun intended) because
> every keyword is implicitly defined to be a constant bound to itself,
> and you can't rebind constants.

Yes, which is great.

> But imagine if instead of being bound by DEFCONSTANT, keywords were
> instead bound by DEFPARAMETER. Then you could do, e.g.:
>
> (let ((:x 1)) :x) --> 1
>
> Yes, I know, you look at that and think Blech! That would break all
> kinds of things, and you're right, it would.

No it wouldn't because nobody does that today. But the problem is that
:x is still just :x outside of that lexical scope. And pieces of data
in that lexical scope are outside of that lexical scope:

:x may produce 1, but (car '(:x)) doesn't.

> NOT break is that it would not cause symbol naming conflicts.
>
> So now imagine a hypothetical lisp that differs from CL in the following
> respects:
>
> 1. The reader produces keywords by default
> 2. The names of lexical bindings are keywords, not symbols
> 3. There is a reader macro on #\: that reads :x as (quote x), which is
> a list of two elements, both of which are keywords.
> 4. EVAL is just like the usual Lisp 1.5 eval, except that the ENV
> argument uses keywords for keys rather than symbols. In the default
> environment, the keyword QUOTE is bound to a fexpr of one argument that
> returns that argument.
>
> In such a Lisp you could write:
>
> (let ((x 1)) (f :x x))
>
> and it would do exactly the same thing as that code does in CL. And the
> result from your example above would be "FOO" just as you expect.
>
> Are you with me so far?

I think it might be better like this:

1. The reader produces keywords by default

2. Keyword are interned in a global table (like a package,
but it's only for keywords and there is only one).
So if a keyword X escapes from one lexical scope and
travels into another, it is the same object as the X
occuring in that lexical scope.

2. The names of lexical bindings are keywords, not symbols

3. If a keyword is evaluated which has no apparent lexical
binding, this is not a free reference. Rather, the value
is that symbol itself. So it is not necessary to quote
keywords: anything you don't bind is a keyword.

4. Programmers who want to distinguish never-bound keywords
from usually-bound keywords can use a convention
analogous to *earmuffs* for CL specials. That convention
can be foo: for Europeans, RG and :foo for sane people.
The colon is just a constituent. So if there is no
binding for :foo, then (eq :foo (car '(:foo))).

4. EVAL is just like the usual Lisp 1.5 eval, except that
the ENV argument uses keywords for keys rather than
symbols. In the default environment, the keyword QUOTE
is bound to a f***r of one argument that
returns that argument.

[Please *** out dirty words; there are children reading.]

I don't see how dynamic bindings fit into this and also regular symbols which
are not keywords. Also, hygiene in macros?

RG

unread,
Mar 10, 2012, 7:14:39 PM3/10/12
to
In article <87obs4h...@black.wyrd.be>,
Cool! I was able to paste Pierre's code into CCL and SBCL it actually
worked! Alas, my ancient CLisp (2.39) does not seem to have
add-loop-path, but maybe that just means it's time to upgrade.

Still, the Right Way to have extensible loops is to use iterators:

http://rondam.blogspot.com/2008/02/joy-of-iterators.html

:-)

rg

RG

unread,
Mar 10, 2012, 10:04:36 PM3/10/12
to
In article <201203101...@kylheku.com>,
Kaz Kylheku <k...@kylheku.com> wrote:

[Bunch of stuff we agree on elided.]

> >> The punctuation on keywords is quite helpful in argument or property
> >> lists,
> >> especially long ones. It says "this is the indicator, and the thing to the
> >> right must be the property".
> >
> > Yes. But that still leaves open the question of whether or not this
> > helpful feature should be baked into the design of the language, or
> > whether it should be, for example, a programming convention like
> > *earmuffs*.
>
> But *earmuffs* is pretty much baked into the language.

Not according to what I mean by "baked in". I don't like earmuffs. I
prefer to designate dynamic variables using a dollar sign, e.g. $var.
Nothing in CL prevents me from doing that. I can even shadow the
predefined globals with symbol macros (e.g. (define-symbol-macro
$print-base *print-base*). I can even write a function that will go
through all of the symbols in the common-lisp package and define these
symbol macros for me automatically in about three lines of code.

But if I want my keywords to look like this: instead of :this without
breaking the rest of the language I have to do some pretty massive
readtable hacking. This is what I mean by being "baked in" to the
language (as opposed to being baked into the culture).

> > Agreed. But to reiterate, the issue is not whether sigils are useful,
> > but rather whether the syntax for them should be unalterably baked into
> > the specification of the language. In a "programmable programming
> > language" like CL I believe the design principle should be that you
> > ought not bake things into the language unless there's a compelling
> > reason.
>
> A broad rule for a class of symbols that they evaluate to themselves is
> pretty cool. nil and t ought to have been keywords, :nil and :t.

I agree with you about the end goal. But building self-evaluating
symbols into the language is not the only way to accomplish this, and it
has some pretty significant drawbacks, not least if which is that if you
find that you've gotten the lexical convention wrong then it's a lot
harder to change.

Much better if you want self-evaluating symbols to build yourself a
little reader macro that reads :foo as (progn (defconstant \:foo '\:foo)
'\:foo)

> >> >> But for keyword tokens to be "non clunky" (identifiers with zero
> >> >> characters
> >> >> of
> >> >> additional syntax) maybe other things in the language would become
> >> >> clunky,
> >> >> possibly such that the overall clunkiness increases.
> >> >
> >> > Only if you do it wrong. It is a pretty minor tweak to CL's current
> >> > design to have the best of both worlds. All you need to do is to add a
> >> > level of indirection. Instead of:
> >> >
> >> > string->(reader)->symbol
> >> >
> >> > do:
> >> >
> >> > string->(reader)->keyword->(lexicon)->symbol (or whatever)
> >>
> >> So everything coming out of the reader is a keyword.
> >
> > In a perfect world, yes.
> >
> >> I'm trying to form a picture of how that would work.
> >
> > http://flownet.com/ron/lisp/lexicons.pdf
> > http://flownet.com/ron/lisp/lexicons.lisp
>
> Is this new in the latest version or just from old behavior?

New relative to what? The lexicons code underwent a major overhaul
about two years ago, and pretty much hasn't been touched since then.

> >> Keywords connect remote parts of a program together so they can't be tied
> >> to
> >> lexical scopes. Or can they?
> >
> > Not sure what you mean by this. Symbol name collisions are inherently a
> > dynamic phenomenon.
>
> I just mean that they are part of the expression of interfaces.

That doesn't help much. There are lots of different kinds of
interfaces, particularly if you're talking about "remote parts of a
program." In the age of the Internet, that could mean a lot of
different things.

> > That's one of the coolest thinks about lexical scopes: they naturally
> > form a hierarchical structure so that there is an obvious rule for
> > resolving name conflicts. Indeed it is so obvious that people don't
> > even THINK of lexical name conflicts as conflicts. The rule is: inner
> > scopes shadow outer scopes. That rule turns out to be all you need.
>
> That rule is error-prone. That's why we have a -Wshadow gcc warning.

Is that the reason? I thought it was because C++ was a horribly broken
language. Do any Common Lisp compilers have an equivalent warning?

> > I completely agree that (f 'keyword value) is unaesthetic. It should be
> > (f keyword: value). But the way CL is currently defined, that is
> > necessarily a syntax error unless you muck with the reader to make #\: a
> > constituent, but that carries a steep price, namely, the loss of
> > read-print consistency.
>
> Me, I don't care if it goes to the front or back. I'm AC/DC.

I've been high, I've been low
I've been "yes" and I've been "oh hell no!"
I've been rock and roll and disco
Won't you save me San Francisco?

> > The names of symbols should be keywords (i.e. immutable strings), not
> > (mutable) strings.
>
> Interesting. So (name-equal x y) reduces to (eq (symbol-name x) (symbol-name
> y)).

Yep.

> > The leaf nodes of programs should be keywords, not
> > symbols. The semantics of programs made of keywords are mapped onto the
> > semantics of programs made of symbols by adding a pass that maps
> > keywords onto their corresponding bindings in the current lexicon, which
>
> If keywords have bindings they are symbols, which we said they are not. :)

No, that's not true. A keyword can have a lexical binding without
becoming a symbol. This is the reason that symbols with lexical
bindings can be "compiled away", and also the reason that this doesn't
work:

(let ((x 1)) (symbol-value 'x))

to the perennial confusion of newbies.

> Basically they might as well be symbols, but in a special category.
>
> Shit, actually I had nearly the same idea several days ago. The idea
> was that there should be symbols which are not in any package.

There are. They are called uninterned symbols. But uninterned symbols
are different from keywords.

> And that symbols should be separately interned in a package
> and in the "no package" zone.

That's starting to sound a little incoherent.

> > I would handle this with reader macros. If you wanted CL-style keyword,
> > just define a reader macro on #\: that reads :foo as (quote foo).
>
> But then '(:foo bar) is (quote ((quote foo) bar)). No thanks! I want :foo
> to be the same thing whether it is code or data.
>
> (This is a little bit like (define nil '()) in Scheme. It fails to
> make '(nil) a list of an empty list.)
>
> A macro that gives me a : spelling for ' is not that productive.

Good point. How about this:

(defun keyword-reader (stream char)
(unread-char char stream)
(let ((*readtable* (copy-readtable nil)))
(let ((s (read stream)))
(eval `(defconstant ,s ',s))
s)))

(set-macro-character #\: 'keyword-reader t)


> > But imagine if instead of being bound by DEFCONSTANT, keywords were
> > instead bound by DEFPARAMETER. Then you could do, e.g.:
> >
> > (let ((:x 1)) :x) --> 1
> >
> > Yes, I know, you look at that and think Blech! That would break all
> > kinds of things, and you're right, it would.
>
> No it wouldn't because nobody does that today. But the problem is that
> :x is still just :x outside of that lexical scope. And pieces of data
> in that lexical scope are outside of that lexical scope:
>
> :x may produce 1, but (car '(:x)) doesn't.

Of course it doesn't. (let ((x 1)) (car '(x))) doesn't return 1 either.

BTW, we can actually do this experiment:

? (defun keyword-reader (stream char)
(unread-char char stream)
(let ((*readtable* (copy-readtable nil)))
(let ((s (read stream)))
(eval `(defparameter ,s ',s))
s)))
KEYWORD-READER
? (set-macro-character #\= 'keyword-reader t)
T
? (list* =x '(=x) (let ((=x 1)) (list =x (car '(=x)))))
(=X (=X) 1 =X)

> I think it might be better like this:
>
> 1. The reader produces keywords by default
>
> 2. Keyword are interned in a global table (like a package,
> but it's only for keywords and there is only one).
> So if a keyword X escapes from one lexical scope and
> travels into another, it is the same object as the X
> occuring in that lexical scope.
>
> 2. The names of lexical bindings are keywords, not symbols
>
> 3. If a keyword is evaluated which has no apparent lexical
> binding, this is not a free reference. Rather, the value
> is that symbol itself. So it is not necessary to quote
> keywords: anything you don't bind is a keyword.
>
> 4. Programmers who want to distinguish never-bound keywords
> from usually-bound keywords can use a convention
> analogous to *earmuffs* for CL specials. That convention
> can be foo: for Europeans, RG and :foo for sane people.
> The colon is just a constituent. So if there is no
> binding for :foo, then (eq :foo (car '(:foo))).
>
> 4. EVAL is just like the usual Lisp 1.5 eval, except that
> the ENV argument uses keywords for keys rather than
> symbols. In the default environment, the keyword QUOTE
> is bound to a f***r of one argument that
> returns that argument.
>
> [Please *** out dirty words; there are children reading.]

Yeah, more or less. Whether keywords are uniquified strings or
symbol-like objects without bindings interned in a global table that is
like a package (but not really) is just quibbling over terminology.

> I don't see how dynamic bindings fit into this and also regular symbols which
> are not keywords. Also, hygiene in macros?

Don't forget slot names. That actually turns out to be the hardest
problem to solve (and in fact it is the one thing that the current
implementation of lexicons does not handle properly).

Explaining how it all works would take me longer than I have at the
moment. I would refer you to the paper and the implementation if you
can't stand to wait. Otherwise I'll try to write something up in the
next few days.

rg

Kaz Kylheku

unread,
Mar 11, 2012, 6:12:44 AM3/11/12
to

Kaz Kylheku

unread,
Mar 11, 2012, 6:23:36 AM3/11/12
to
On 2012-03-11, Kaz Kylheku <k...@kylheku.com> wrote:
> On 2012-03-11, RG <rNOS...@flownet.com> wrote:
>> I don't like earmuffs.
>
> Oh really.
>
> http://www.ladiesfashion.jp/images/coordinate/201201/s/_MG_5763.JPG

Closer look:

http://www.ladiesfashion.jp/images/coordinate/201201/s/_MG_5776.JPG
http://www.ladiesfashion.jp/images/coordinate/201201/s/_MG_5799.JPG

(let ((there-be *earmuffs*)))

RG

unread,
Mar 11, 2012, 2:56:17 PM3/11/12
to
In article <201203110...@kylheku.com>,
Kaz Kylheku <k...@kylheku.com> wrote:

> On 2012-03-11, RG <rNOS...@flownet.com> wrote:
> > I don't like earmuffs.
>
> Oh really.
>
> http://www.ladiesfashion.jp/images/coordinate/201201/s/_MG_5763.JPG
>
> No?

No.

? (in-package :lexicons)
#<Package "LEXICONS">
? (ldefvar x 1)
1
? (defun foo () x)
FOO
? (let ((x 2)) (list x (foo)))
(2 1)
? (dlet ((x 2)) (list x (foo)))
(2 2)

And as an added bonus:

? (defun undefined-global-demo () y)
;Compiler warnings :
; In UNDEFINED-GLOBAL-DEMO: Deferring lexical binding of Y
UNDEFINED-GLOBAL-DEMO
? (dlet ((y 1)) (undefined-global-demo))
; Warning: Deferring lexical binding of Y
; While executing: REF-FORM, in process Listener(6).
> Error: Y is not a global variable
> While executing: %DLET, in process Listener(6).
> Type cmd-. to abort, cmd-\ for a list of available restarts.
> Type :? for other options.
1 >
? (ldefvar y 1)
1
? (dlet ((y 1)) (undefined-global-demo))
Resolving binding of Y
1
?

rg

namekuseijin

unread,
Mar 11, 2012, 7:39:49 PM3/11/12
to
Em sexta-feira, 9 de março de 2012 16h29min06s UTC-3, Chiron escreveu:
> On Thu, 08 Mar 2012 14:38:54 -0800, namekuseijin wrote:
>
> > aside from the thick layers of smelly historical cruft and the whole
> > lisp-2 slotty nature, there's not much bad habits indeed. At least it's
> > lisp.
>
> I think it would be more helpful if you could specify exactly what you
> mean by "cruft," since the term is vague at best. So far, as a rank
> noobie, CL looks pretty good to me. Perhaps you could enlighten me as to
> the crufty parts.
>
> Also, I don't understand what you mean by "slotty" behavior - is that a
> term of art, or a misspelling, or what? The only "definition" I could
> find for slotty was a conflation of "slutty" and "hottie." I don't see
> how this could apply to your comment.

lisp-2 Lisps have "slots" for (at least) function and value assigned to the same symbol. It's a hack and a mess and is what prevents you from simply writing a clean (map (lambda (x) (* x x)) '(1 2 3 4 5))

They remind me of python's slots too, which is another unbearable behaviour to an otherwise nice language.

http://en.wikipedia.org/wiki/Cruft

namekuseijin

unread,
Mar 11, 2012, 7:48:07 PM3/11/12
to
Em sexta-feira, 9 de março de 2012 07h02min40s UTC-3, Pascal J. Bourguignon escreveu:
> Leandro Rios <leandropr...@gmail.com> writes:
>
> > El 08/03/12 14:58, namekuseijin escribió:
> >> On Thursday, March 8, 2012 7:06:23 AM UTC-3, Pascal J. Bourguignon wrote:
> >>> namekuseijin<nameku...@gmail.com> writes:
> >>>
> >>>> we hang on comp.lang.lisp because we think Lisp is worthwhile without
> >>>> all the cruft from ages past. We just don't like the CL zombie.
> >>>
> >>> (defpackage "MODERN-LISP"
> >>> (:use "CL")
> >>> (:export "FIRST" ; not "CAR"
> >>> "REST" ; not "CDR"
> >>> "SETF"
> >>> …))
> >>>
> >>> (defpackage "MY-PROGRAM"
> >>> (:use "MODERN-LISP"))
> >>> (in-package "MY-PROGRAM")
> >>>
> >>> (first '(1 2 3))
> >>
> >> I'm using Racket, which is a batteries-included Scheme and more. Previously I used my own implementations in R5RS of such common and useful functions and idioms.
> >
> > Are you aware that he's pulling your leg?
>
> No, I'm dead serrious. You don't have to wait for racket developers to
> design the language you like. With Common Lisp, you can make it
> yourself. Just define a package exporting the operators you want in
> your language and godspeed!

yes, you can make it yourself (as you can in racket as well) and not play nice with the world at large, which is one of the very reasons why the old Lisp world has crumbled (and turned into the CL zombie).

Java, despite all the bad naming, at least got that right: a language based around a few reasonably powerful builtin constructs leading to code standardization and reuse. Nothing of "design your own (lisp-like) language on-the-go and marvel as no one uses it or libs created with it".

Kaz Kylheku

unread,
Mar 11, 2012, 8:20:58 PM3/11/12
to
On 2012-03-11, namekuseijin <nameku...@gmail.com> wrote:
> Em sexta-feira, 9 de março de 2012 16h29min06s UTC-3, Chiron escreveu:
>> On Thu, 08 Mar 2012 14:38:54 -0800, namekuseijin wrote:
>>
>> > aside from the thick layers of smelly historical cruft and the whole
>> > lisp-2 slotty nature, there's not much bad habits indeed. At least it's
>> > lisp.
>>
>> I think it would be more helpful if you could specify exactly what you
>> mean by "cruft," since the term is vague at best. So far, as a rank
>> noobie, CL looks pretty good to me. Perhaps you could enlighten me as to
>> the crufty parts.
>>
>> Also, I don't understand what you mean by "slotty" behavior - is that a
>> term of art, or a misspelling, or what? The only "definition" I could
>> find for slotty was a conflation of "slutty" and "hottie." I don't see
>> how this could apply to your comment.
>
> lisp-2 Lisps have "slots" for (at least) function and value assigned to the
> same symbol. It's a hack and a mess and is what prevents you from simply

You know, if you keep trolling like this, you will need a pet name. Candidates:

namakusaijin

mendokusaijin

Some peple like Lisp-2, for solid reasons.

I do too and so I made TXR's Lisp dialect a Lisp-2. TXR started out not even
having functions, but pattern functions (which are in their own name space).
So when the Lisp function namespace came in, it was already not the first
namespace.

Lisp-2 is good for writing macros without fiddling around with packages or,
heaven forbid, a hygienic macro system. You can use list as a variable name,
without breaking a macro expansion which uses list, and so macro expansions
don't have to worry about that.

In Lisp-2 You can write Lisp code with macros without using the package system,
and never run into function hygiene issues, because to run into that, you would
have to write obviously stupidly named lexical functions, like (labels ((append
() ...))).

I have found a nearly ideal solution and that is to have a way to bend the
evaluation rules to create a "pocket of Lisp-1" inside Lisp-2.

The inconveniences of Lisp-2 are well-understood and acknowledged by Gabriel
and Pittman in ``Technical Issues of Separation in Function Cells and Value
Cells''.

To address them, I invented an operator called (dwim ...). Inside dwim,
expressions are evaluated according to Lisp-1. The actual evaluator that
is used is an alternate one, just for the "top level" forms (relative
to dwim), not for their constituents. Under this evaluator, the two namespaces
are folded (with precedence going to the variable namespace). Furthermore, the
first argument expresion of dwim is treated as a funcallable object (not just a
function). However, the first argument must not be an operator. I.e. the
Lisp-2 pocket does not see the Lisp-2 macros. This is important.

DWIM means: dispatch in an way that is intelligent and meaningful.

Now instead of writing (dwim ...) you can use the syntactic sugar [...].

> writing a clean (map (lambda (x) (* x x)) '(1 2 3 4 5))

I think you made a mistake here, because this is Common Lisp:

(mapcar (lambda (x) (* x x)) '(1 2 3 4 5))

lambda is a macro that produces (function (lambda ...)).

Maybe you're so used to criticizing Lisp as a kind of verbal habit that you
don't even remember what the actual problem is any more, just that it has
something to do with lambdas and maps.

To jog your memory, the usual complaint is that if we make a function called
square, we cannot just write:

(mapcar square '(1 2 3 4 5)) ;; need (function square) or #'square

And if we have a function stored in a variable F, we
cannot write

(f arg) ;; need (funcall f arg)

For the other ways of application with a form that evaluates
to a function that issue is moot because all of these work the same way in
Lisp-2 as in Lisp-2:

(apply f arg)
(mapcar f args)

It's just when f is the first argument.

My dwim/square brackets invention solves that:

[mapcar square '(1 2 3 4 5)] ;; alternate evaluation rules

[f arg]

Operators will not work:

[let ((a b))] ;; nonsense.

This is fine because this notation is for functional application, not for
working with syntax.

This restriction discourages the wanton use of square brackets for everything.
If the above worked, you could write all code with square brackets and then
you would end up doing stupid things like:

[list a b c] ;; inside a macro expansion

and now you capture a variable called list!

The style of programming encouraged is to use the round brackets, and only whip
out the [ ... ] when the first argument is a value, or when some of the
arguments other than the first are function names. I.e. when the "DWIM"
intelligent dispatch is needed.

The remaining risk is that if you write for instance [mapcar ...]
in a macro expansion, that could capture a variable called mapcar.
Well, in a macro expansion, what you can do is: don't do that.
Write the slightly less convenient (mapcar ...). Macros don't
have to be super-easy to write (as long as they are not exceedingly
difficult to write). The have to be super-easy to use.

On lists, vectors and strings, the syntax performs indexing, and the square
brackets resemble the array brackets in some other languages.

[a 3] ;; fourth element of array

[h 'd] ;; lookup 'd in hash h.

Lisp-2 with dwim/[] is a beautiful thing (and even without).

Kaz Kylheku

unread,
Mar 11, 2012, 8:27:32 PM3/11/12
to
On 2012-03-11, namekuseijin <nameku...@gmail.com> wrote:
The CL world is quite vibrant, with active development on various fronts.

> Java, despite all the bad naming, at least got that right: a language based
> around a few reasonably powerful builtin constructs leading to code
> standardization and reuse. Nothing of "design your own (lisp-like) language
> on-the-go and marvel as no one uses it or libs created with it".

Whether or not someone uses your language or libs only matters if they are
paying.

If you invent a language today, no matter how great or popular, you will likely
not make a dime other than maybe from lectures and speaking engagements and
such.

It will have to be open sourced, first of all, and liberally licensed to
get any kind of hold.

That kind of thing is nearly impossible to sell.

The same goes for libs, which are just the same stuff as language (as we know
in this NG).

Writing languages and libs is just a hobby to amuse yourself, funded by a
dayjob.

Users who use an /application/ don't care what language or libs are under the
hood.

You don't have to play with the rest of the world if you're trying to make a
product. You're in competition with the rest of the world, so if you come up
with a great lib, you keep it to yourself.

People making languages and libs are just doing free work, and someone else
laughs to the bank. Their reward is having fun.
It is loading more messages.
0 new messages