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)
(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?)))
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.
> 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:
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:
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:
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:
> 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.
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.
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! "))
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!
On Wednesday, March 7, 2012 11:20:17 AM UTC-5, Juanjo Garcia wrote:
> 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! "))
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:
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.
> 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.
> 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",
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.
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:
> 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.
> 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?
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.
On Wednesday, March 7, 2012 5:21:52 PM UTC-3, Teemu Likonen wrote:
> * <namekusei...@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
> 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?
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.
> > 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.
namekuseijin <namekusei...@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.
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
> 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)
> (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?)))
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.
> 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)
> (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'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
namekuseijin <namekusei...@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?)
> 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]
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.
> > > 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.