What you are describing (and quite well) is the top-down programming practice. There's a big problem with it, though: in the real world, things change. As others have pointed out, you can't be guarenteed to be able to hammer down a specification that will be satisfactory for a year, or a month, sometimes even a week or a day. Some customer, some manager, or whoever, will demand a change in the final product. What will you do then? You will have to change your entire structure around and that can be extremely difficult.
Fortunately there are other ways of approaching the problem. One of them is called the bottom-up approach. The basic idea is to create a mini-language that one can better formulate your problem in, and then start putting the pieces together. This is complimented by dynamic semantics that languages such as Common Lisp or Smalltalk have. Incremental, interactive compilation and development is well supported by these environments. The code winds up being self-documenting because you wrote it in a mini-language! Weirdly obfuscated--but necessary--as well as commonly used pieces of code can be abstracted with Lisp macros. Changing your data-structures is no problem, already in-use data-structures can be dynamically updated (and you can control how it happens). Errors are handled by the exceptional condition system (no pun intended) and the program can be continued from where you left off, after being fixed. Always you have a working, running codebase.
Would be a shame if your "Computer Science" education only prepared your for the job market and didn't teach you any computer science though, eh? I think that's what the OP was somewhat annoyed about and I agree. Computer science isn't about learning a trade; may as well become an apprentice. It's about learning mathematics, logic, and computability. Just because many schools offer a "Computer Science" dept that actually teaches "Software Engineering" doesn't mean that "Computer Science" equates to Java-hacking or something equally inane.
Your college education in Computer Science should teach you the ins and outs of the lambda calculus, higher-order functions, the nature of the computable, algorithm design and analysis, formal logic, etc... so on and so forth. You should have no trouble adapting to any sort of computer tools after that; your skills won't be obsolete in 3 years. What in the world does Flash have to do with all that? Do yourself a favor, go to a trade school if all you care about is learning trade-tools, and save yourself some money.
(Not that I object to taking classes in such tools, but they are far, far from what your focus should be)
I agree with many of your points but you don't seem to be familiar with Common Lisp and CLOS; there's more than multiple-inheritance. How about method combination and multiple-dispatch to start? Why did Smalltalk ditch multiple-inheritance anyway? Flavors, Loops, and CLOS all have solved it using various topological-sort methods (or worked around the diamond problem anyway).
What about support for multiple paradigms? Great; Smalltalk does OO really well (as well as single-dispatch and single-inheritance can, anyway). But there's other ways of programming, whatever marketting hype might tell you. There's also more than sugar to syntax; Lisp macros are a great tool for abstraction and language-construction. Lispers create sub-languages, to solve their problem in, all the time; and then they use it to solve similar problems as well (talk about reusability).
Common Lisp isn't the greatest language ever (and the ANSI standard isn't the best it can get) but it's one of the most flexible languages you'll find out there, and that can make up for most of the shortcomings. And very few things surpass it either.
While we're on the subject I might as well point out a few of the Franz Allegro CL developers' problems with the Microsoft CLR (some of which also are relevant to Smalltalk):
Multiple-dispatch not supported
Complex argument-lists not supported
Method dispatch determined statically at runtime (a killer for dynamic languages)
Obviously Microsoft was only thinking about C# and similarly crippled languages when they drew up the design of CLR. Supposedly the Microsoft programmers listened and perhaps we will see some changes, but I'm not holding my breath.
You are right in the sense that type information
is not known at compile-time. But the notion
that "types are automatically inferred concepts
used for (automatic) software verification" sounds
rather ML-centric:). Types have a very distinct
mathematical meaning as sets of valid values.
Think of such concepts as domain and range, and then tell me that "types are not part of an
actual algorithm".
I wasn't very clear in my original post about this
but I think you are mixing up strong typing with
dynamic typing. Strong typing ensures that type
semantics must be followed precisely. Dynamic
typing by itself is not a true type system because
it's not the whole picture.
Lisp has dynamic and
strong types; ie. the number 3 is an integer and
it may be bound to any variable, the type
information being carried along with it. It may be used by operations which expect integers, but trying to apply a character operation to it would fail with a runtime exception. Fortunately Lisp has an excellent condition system. (Note
that certain compilers can perform optimizations
that eliminate the need to carry type information
at runtime. Python, used by CMUCL and SBCL,
can perform this sort of optimization as well as
various static type inference analysis. In Lisp,
though, static type analysis is an optimization;
not a necessity.)
I understand that this makes
it very hard to analyze a program statically
at compile-time, and that there is a place for
such analysis, but remember that the world is
a dynamic place and not every program you write
will fit well into the static mold. That's
basically the reason why I like Lisp. It's
not a mathematical reason, but a practical
one.
You are a bit confused. Dynamic typing implies that values have types; not variables. Please get your facts straight before calling Lisp a "historical" artifact. I think there are quite a few tricks left in the old bag yet. Common Lisp
looks to be quite alive and kicking, thank you, and
it seems that it would be well worth your while
to learn a bit from it.
You might start by noting that people are raving in other threads
of the ability for Java compilers to mix interpreted and compiled code at runtime. You might want to note that Lisp compilers have been doing that for decades. How about decent GC? Or good development environments? CL compilers all seem to have the nicest IDEs, because CL is such a dynamic language. Oh it doesn't conform to functional ideals as a result; but that's okay: Lisp ain't functional anyway. It's not imperative or OO either; it's any and all. It's good to be flexible.
There is a reason why many programming techniques were pioneered or prototyped in Lisp.
Expressing complex algorithms, perhaps, but it's a pain for RAD. Having to determine all the types while you code puts quite a burden on the programmer; it's often orthogonal to the problem and just wastes your time which should be spent working out the algorithm. Also it sucks when you want to express more complicated types such as (or fixnum string) or a type that is selected by a predicate function.
Also the CMUCL compiler "Python" will do static type inferencing with as much as it can. I believe other implementations are starting to catch on to this, but it's mostly for optimization purposes not for enforcement of type-safety (though warnings will be emitted if a conflict is found). To enforce the matter would be to lose
the Lisp dynamicism that we Lisp coders have come
to like. The ML compilers will refuse to compile
functions that don't typecheck but Python will simply insert a run-time type-check and let it go.
The functional style is far more maintainable than the imperative style, for any intelligent person (being able to program in Perl, VB, etc does not make you intelligent). It's so maintainable that you can prove its correctness using formal logic. If that's not an argument for functional-style programming then I don't know what is.
If you still count parenthesis you are a fool, plain and simple. There are many editors out there which count parenthesis for you, amazingly enough, and some go beyond by providing navigation commands based on S-expressions and automatic indentation. If you're still in the stone age, I'm sorry for you; stop using your crappy line-editors and join the modern world.
And the semi-colon would indicate a comment, btw
The bit about Excel is interesting. Care to elaborate?
Re:Rule 1 of Efficient Lisp: Lisp is not functiona
on
Common Lisp: Inside Sabre
·
· Score: 2, Informative
What is LISP bad at? Well, its libraries can be rather weak and nonstandard (although ANSI Common LISP itself comes with a large array of useful functions); GUI stuff, multithreading, and networking all fit in this category and are often implementation specific. (Of course, this is nothing to do with the language itself but just with what tools are available.) Its use for really low level bit-twiddling stuff is somewhat awkward. Iteration in LISP suffers somewhat from being only a little bit more powerful than iteration in C; the upside is you can still combine it with all the other great stuff in LISP, but the downside is that the parenthisis-style syntax, which is so much better for writing macros and functional code, only clutters up iterative code.
Multithreading is found in the commercial Common Lisp environments and in the CMUCL/x86 port. CLOCC maintains several libraries for cross-implementation usage of non-standard features such as networking. CLIM solves the GUI problem, the problem is that there was no free CLIM implementation for a long time due to legal issues. Finally, a free CLIM is being developed: McCLIM and I'm sure they can use help. As for iteration,
perhaps your mind has been clouded by Paul Graham;
who has an irrational fear of the LOOP macro.
The LOOP macro, however, provides one of the most
powerful iteration constructs I've seen; and it's
not parenthesized like the DO macro is. Example:
(loop for x from 1 to 10 summing x do (format t "~&~A" x))
Prints out a list of numbers from 1 to 10 and
the sum of them all at the end.
The equivalent DO:
(let ((sum 0))
(do ((x 1 (1+ x)))
((> x 10) sum)
(incf sum x)
(format t "~&~A" x)))
Also the LOOP macro provides yet more keywords for all sorts of handy features which aren't so easy to do with DO; collecting, appending, finally, initially, if/else, etc... Please read the
section in the HyperSpec about LOOP,
Section 6.1
I even once wrote a finite-state-machine entirely
within a single LOOP macro that processed the
Unix mbox format. It's quite nearly a language
in itself (speaking of which, FORMAT is in a
similar category, except for formatted output
instead).
I would argue that CL is better at bit-twiddling than C is. Take a look at the
CLHS
Section 12.1.1.3.2 and the functions BYTE, LDB, and DPB. It's a different perspective than the C view, but more interesting since you can extract and replace any number of bits that you want. Also it's not dependent on 8 bits per byte.
Still, there are many areas where CL just doesn't have the sheer effort put into the libraries, likely due to the lack of manpower.
Particularly in the Free-software category; Lisp
has a tradition extending long before the current
wave of Free-software and while many commercial
vendors will provide good support and lots of
libraries, the Free implementations often lack
this. Many Lisp programmers use the commercial
Lisps and have the features they want; if not they
ask/pay the vendor to implement them. Another
issue is that Common Lisp is not Unix-centric,
unlike *ahem* most popular languages today. CL
was designed to be workable in any environment,
so the designers could not take shortcuts with
things like pathnames, executable formats, system
libraries, or other system-dependent issues.
After all; Common Lisp was conceived in the era
of the Lisp Machine. Unix was just another OS
in the vast array. Finally, it is unfair to compare the Common Lisp standard against a single-implementation language such as Perl.
Standards cost $$$$$ and require a great deal of
effort and responsibility. If a Common Lisp
implementation does not comply with the standard
then it is at fault. But with Perl, whatever Larry Wall does goes. Even if it breaks all your
code; too bad.
(Back to the OP's topic) Franz's Success Stories has plenty of examples of Lisp
applications. Franz develops Allegro Common Lisp,
a popular commercial CL.
Speed can range anywhere from what you say, to
worse, to better than C. It all depends on
how well you write your code, and how good the
compiler is.
As for far from the machine? Uh, ok...:
CMU Common Lisp release x86-linux 3.0.4 18c+ 17 November 2001 build 2828
Loaded subsystems:
Python 1.0, target Intel x86
CLOS based on PCL version: September 16 92 PCL (f)
* (defun fixnum-add (a b)
(declare (type fixnum a b)
(optimize (speed 3) (safety 0)))
(the fixnum
(+ a b)))
FIXNUM-ADD is an internal symbol in the COMMON-LISP-USER package.
Function: #<Function FIXNUM-ADD {480AD151}>
Function arguments:
(a b)
Its defined argument types are:
(FIXNUM FIXNUM)
Its result type is:
FIXNUM
* (fixnum-add 3 4)
7
Re:Rule 1 of Efficient Lisp: Lisp is not functiona
on
Common Lisp: Inside Sabre
·
· Score: 2, Interesting
A few notes:
Common Lisp does not guarantee tail call optimization, but most decent implementations do it.
Common Lisp does not guarantee a garbage collector either, but again, most implementations gotta do it;)
Tail-recursion is nice, but macros like LOOP
with the extended syntax are quite powerful. I
would say that Common Lisp is better at iteration
than most other languages.
Your implication that Lisp lacks objects is false. In fact you are wrong: not every type in
Java is an object (int, char, etc..). In Common Lisp, every type is an object that has its own
identity. You should read Kent Pitman's article
on the misappropriation of the term "Object-
oriented"
Also you should read the section of the CLHS that discusses CLOS: The Common Lisp Object System, which is far more powerful object-system than the pathetic Java/C++ one: with multimethod dispatch, method combination, and multiple inheritance. If you feel adventurous, read the Art of the Meta Object Protocol (AMOP) which you can buy for ~ $40, which discusses how to implement CLOS while exposing the internals in
a controlled fashion; which allows you to modify
the behavior of CLOS easily.
Yes, Common Lisp is not all there is to Lisp but it is the most widely used one today. Consult the Common Lisp HyperSpec for more information:
CLHS
UNWIND-PROTECT is an external symbol in the COMMON-LISP package.
Special form documentation:
Unwind-Protect Protected Cleanup*
Evaluate the form Protected, returning its values. The cleanup forms are
evaluated whenever the dynamic scope of the Protected form is exited (either
due to normal completion or a non-local exit such as THROW).
More information can be obtained from the Hyperspec
I personally use IMHO with mod_webapp to write web applications for work. People write similar things in Java, but Lisp is a far more suitable language due to the interactive runtime compiler and introspective capabilities. I find CLOS to be a better, more flexible object system for these tasks than the Java/C++ model as well. Multi-method dispatch, multiple-inheritance, call-next-method,:around methods, and even some Meta-Object Protocol I have used in my programs. And I nearly forgot the really neat HTML macros that let you write out HTML in s-expressions. It's much less clunky writing HTML in Lisp than HTML as HTML, especially in Emacs.
I do believe they have a quote for this: "Those who do not learn from history are bound to repeat it." Which has also been stated as "Those who do not learn Lisp are bound to reinvent it." Witness Python and Ruby.
Actually the question should be: Do we really need another C compiler? Besides the fact that C is a poor language to optimize (weak typing, crappy calling conventions, broken arrays, you name it), it's about as close to assembly as a "high level" language gets and assembly is not a very good way to write quick and easily maintained code. Better to work on smarter compilers for languages that allow one to work on a higher level of abstraction. Projects such as CMUCL, SBCL, and OCaML could always use some help.
I seem to recall this very document being
noticed by the "Slashdot crowd" at least
twice previously. Every so often it
gets reposted and apparently people have
short enough memories that they don't
realize it's the same document.
This looks like a clever assortment of levers
and pulleys to allow a small amount of force
to move a heavy object. Such machines are nothing
strange; my question is, and I was unable to
find a reason, why do you need a kite? Why not
some people (they had plenty of slaves, no?)
pull on the rope instead?
C/C++ gurus have their hands tied--OCaML is a statically inferred, strongly typed language and that's why it's compiler is so damn good. C and C++ are both weakly typed languages (C++ because of C)
and this makes it that much harder for the
compiler to optimize. You might have more luck
optimizing other strongly-typed languages:
You're right, C and C++ are awful languages. C has carved out a niche for itself as a "higher-level" assembly language. C++, on the other hand, I just cannot see very much reason for. It is a language shoehorned into the retrictive C syntax that was designed (or not designed, really) for systems programming, and to work around the flaws they had to implement all sorts of nasty things. It forces you to worry about memory management, which defeats the point of a higher-level language (which lets you reason about the logical structure of your program rather than the nitty gritty).
What I'd like to say about CSS is that it's headed in the opposite direction from just about every other language out there. You see languages like Python and Ruby, slowly they are approaching the abilities of LISP, moving away from Fortran and Algol. CSS seems to me to be a step backwards,
and will probably flop as a result. (But then again, look at the popularity of Perl. I guess there's a lot of masochists out there).
I think I should point out that while Python and Ruby approach LISP, they won't ever be LISP. The critical difference is in the representation of the programs. LISP programs are data. Some have said that if you removed all the parentheses from a properly tabbed LISP program, it would resemble a Python program. This is true, to an extent (never mind the lexical scoping rules and such), but the parentheses are not there just for show. LISP programs are data, and the parentheses give structure to that data at a higher level than ASCII characters: symbols and lists. And you can manipulate that structure with ordinary data-operations. Not to mention, LISP has had native-code compilers for 40 years, so it's better than just a scripting language. (see Successful LISP for further elaboration on these topics)
Which brings me back to your first point: the C preprocessor. I'm sorry to disillusion you, but the C preprocessor is a pitiful thing compared to the LISP macro facility. And it doesn't take too much extrapolation to figure out why.
It's hard to see the point of a scripting language that lacks so much compared to something like Python or Ruby, or even LISP.
This is precisely the movie I've been trying to make work in my DVD player for quite some time now. I always get these scrambled green things and a SIGSEGV. So far, no cow. Here's to another attempt.
Last time I was writing programs in OCaML, my computer hardware crashed and was out of commission for several weeks. I've been too busy
in the time interval to do any more, unfortunately.
According to a good friend, OCaML does not have function polymorphism (such as 'defmethod' in Lisp) but it can be achieved through various hacks.
If you really want to write your own syntaxes
nothing compares to the Lisp macro facility,
(my friend wants to be able to infixify functions
in OCaML, like in SML, but I think that's just
a waste of time;)
All good Lisp compilers can infer types at compile-time, just like the OCaML compiler, and
you can even specify static types and alter the
amount of optimizing a compiler will do. Not only
can you specify static types, but you can specify
ranges as well! For example: (the (integer 0 100) x) specifies that x must be an integer from 0 to 100.
Pattern matching is an interesting feature, but
its not that hard to write a condition to check
for a cons and then do something. Recursive types are also interesting, I need to experiment more with those.
What you are describing (and quite well) is the top-down programming practice. There's a big problem with it, though: in the real world, things change. As others have pointed out, you can't be guarenteed to be able to hammer down a specification that will be satisfactory for a year, or a month, sometimes even a week or a day. Some customer, some manager, or whoever, will demand a change in the final product. What will you do then? You will have to change your entire structure around and that can be extremely difficult.
Fortunately there are other ways of approaching the problem. One of them is called the bottom-up approach. The basic idea is to create a mini-language that one can better formulate your problem in, and then start putting the pieces together. This is complimented by dynamic semantics that languages such as Common Lisp or Smalltalk have. Incremental, interactive compilation and development is well supported by these environments. The code winds up being self-documenting because you wrote it in a mini-language! Weirdly obfuscated--but necessary--as well as commonly used pieces of code can be abstracted with Lisp macros. Changing your data-structures is no problem, already in-use data-structures can be dynamically updated (and you can control how it happens). Errors are handled by the exceptional condition system (no pun intended) and the program can be continued from where you left off, after being fixed. Always you have a working, running codebase.
PERL is twisted and backwards. The real solution is REPL:
(loop (print (eval (read))))
Would be a shame if your "Computer Science" education only prepared your for the job market and didn't teach you any computer science though, eh? I think that's what the OP was somewhat annoyed about and I agree. Computer science isn't about learning a trade; may as well become an apprentice. It's about learning mathematics, logic, and computability. Just because many schools offer a "Computer Science" dept that actually teaches "Software Engineering" doesn't mean that "Computer Science" equates to Java-hacking or something equally inane.
Your college education in Computer Science should teach you the ins and outs of the lambda calculus, higher-order functions, the nature of the computable, algorithm design and analysis, formal logic, etc... so on and so forth. You should have no trouble adapting to any sort of computer tools after that; your skills won't be obsolete in 3 years. What in the world does Flash have to do with all that? Do yourself a favor, go to a trade school if all you care about is learning trade-tools, and save yourself some money.
(Not that I object to taking classes in such tools, but they are far, far from what your focus should be)
I agree with many of your points but you don't seem to be familiar with Common Lisp and CLOS; there's more than multiple-inheritance. How about method combination and multiple-dispatch to start? Why did Smalltalk ditch multiple-inheritance anyway? Flavors, Loops, and CLOS all have solved it using various topological-sort methods (or worked around the diamond problem anyway).
What about support for multiple paradigms? Great; Smalltalk does OO really well (as well as single-dispatch and single-inheritance can, anyway). But there's other ways of programming, whatever marketting hype might tell you. There's also more than sugar to syntax; Lisp macros are a great tool for abstraction and language-construction. Lispers create sub-languages, to solve their problem in, all the time; and then they use it to solve similar problems as well (talk about reusability).
Common Lisp isn't the greatest language ever (and the ANSI standard isn't the best it can get) but it's one of the most flexible languages you'll find out there, and that can make up for most of the shortcomings. And very few things surpass it either.
While we're on the subject I might as well point out a few of the Franz Allegro CL developers' problems with the Microsoft CLR (some of which also are relevant to Smalltalk):
- Multiple-dispatch not supported
- Complex argument-lists not supported
- Method dispatch determined statically at runtime (a killer for dynamic languages)
Obviously Microsoft was only thinking about C# and similarly crippled languages when they drew up the design of CLR. Supposedly the Microsoft programmers listened and perhaps we will see some changes, but I'm not holding my breath.You are right in the sense that type information is not known at compile-time. But the notion that "types are automatically inferred concepts used for (automatic) software verification" sounds rather ML-centric :). Types have a very distinct
mathematical meaning as sets of valid values.
Think of such concepts as domain and range, and then tell me that "types are not part of an
actual algorithm".
I wasn't very clear in my original post about this but I think you are mixing up strong typing with dynamic typing. Strong typing ensures that type semantics must be followed precisely. Dynamic typing by itself is not a true type system because it's not the whole picture.
Lisp has dynamic and strong types; ie. the number 3 is an integer and it may be bound to any variable, the type information being carried along with it. It may be used by operations which expect integers, but trying to apply a character operation to it would fail with a runtime exception. Fortunately Lisp has an excellent condition system. (Note that certain compilers can perform optimizations that eliminate the need to carry type information at runtime. Python, used by CMUCL and SBCL, can perform this sort of optimization as well as various static type inference analysis. In Lisp, though, static type analysis is an optimization; not a necessity.)
I understand that this makes it very hard to analyze a program statically at compile-time, and that there is a place for such analysis, but remember that the world is a dynamic place and not every program you write will fit well into the static mold. That's basically the reason why I like Lisp. It's not a mathematical reason, but a practical one.
You are a bit confused. Dynamic typing implies that values have types; not variables. Please get your facts straight before calling Lisp a "historical" artifact. I think there are quite a few tricks left in the old bag yet. Common Lisp looks to be quite alive and kicking, thank you, and it seems that it would be well worth your while to learn a bit from it.
You might start by noting that people are raving in other threads of the ability for Java compilers to mix interpreted and compiled code at runtime. You might want to note that Lisp compilers have been doing that for decades. How about decent GC? Or good development environments? CL compilers all seem to have the nicest IDEs, because CL is such a dynamic language. Oh it doesn't conform to functional ideals as a result; but that's okay: Lisp ain't functional anyway. It's not imperative or OO either; it's any and all. It's good to be flexible.
There is a reason why many programming techniques were pioneered or prototyped in Lisp.
Expressing complex algorithms, perhaps, but it's a pain for RAD. Having to determine all the types while you code puts quite a burden on the programmer; it's often orthogonal to the problem and just wastes your time which should be spent working out the algorithm. Also it sucks when you want to express more complicated types such as (or fixnum string) or a type that is selected by a predicate function.
Also the CMUCL compiler "Python" will do static type inferencing with as much as it can. I believe other implementations are starting to catch on to this, but it's mostly for optimization purposes not for enforcement of type-safety (though warnings will be emitted if a conflict is found). To enforce the matter would be to lose the Lisp dynamicism that we Lisp coders have come to like. The ML compilers will refuse to compile functions that don't typecheck but Python will simply insert a run-time type-check and let it go.
The functional style is far more maintainable than the imperative style, for any intelligent person (being able to program in Perl, VB, etc does not make you intelligent). It's so maintainable that you can prove its correctness using formal logic. If that's not an argument for functional-style programming then I don't know what is.
If you still count parenthesis you are a fool, plain and simple. There are many editors out there which count parenthesis for you, amazingly enough, and some go beyond by providing navigation commands based on S-expressions and automatic indentation. If you're still in the stone age, I'm sorry for you; stop using your crappy line-editors and join the modern world.
And the semi-colon would indicate a comment, btw
The bit about Excel is interesting. Care to elaborate?
What is LISP bad at? Well, its libraries can be rather weak and nonstandard (although ANSI Common LISP itself comes with a large array of useful functions); GUI stuff, multithreading, and networking all fit in this category and are often implementation specific. (Of course, this is nothing to do with the language itself but just with what tools are available.) Its use for really low level bit-twiddling stuff is somewhat awkward. Iteration in LISP suffers somewhat from being only a little bit more powerful than iteration in C; the upside is you can still combine it with all the other great stuff in LISP, but the downside is that the parenthisis-style syntax, which is so much better for writing macros and functional code, only clutters up iterative code.
Multithreading is found in the commercial Common Lisp environments and in the CMUCL/x86 port. CLOCC maintains several libraries for cross-implementation usage of non-standard features such as networking. CLIM solves the GUI problem, the problem is that there was no free CLIM implementation for a long time due to legal issues. Finally, a free CLIM is being developed: McCLIM and I'm sure they can use help. As for iteration, perhaps your mind has been clouded by Paul Graham; who has an irrational fear of the LOOP macro. The LOOP macro, however, provides one of the most powerful iteration constructs I've seen; and it's not parenthesized like the DO macro is. Example:
(loop for x from 1 to 10 summing x do (format t "~&~A" x))
Prints out a list of numbers from 1 to 10 and the sum of them all at the end.
The equivalent DO:
(let ((sum 0))
(do ((x 1 (1+ x)))
((> x 10) sum)
(incf sum x)
(format t "~&~A" x)))
Also the LOOP macro provides yet more keywords for all sorts of handy features which aren't so easy to do with DO; collecting, appending, finally, initially, if/else, etc... Please read the section in the HyperSpec about LOOP, Section 6.1
I even once wrote a finite-state-machine entirely within a single LOOP macro that processed the Unix mbox format. It's quite nearly a language in itself (speaking of which, FORMAT is in a similar category, except for formatted output instead).
I would argue that CL is better at bit-twiddling than C is. Take a look at the CLHS Section 12.1.1.3.2 and the functions BYTE, LDB, and DPB. It's a different perspective than the C view, but more interesting since you can extract and replace any number of bits that you want. Also it's not dependent on 8 bits per byte.
Still, there are many areas where CL just doesn't have the sheer effort put into the libraries, likely due to the lack of manpower. Particularly in the Free-software category; Lisp has a tradition extending long before the current wave of Free-software and while many commercial vendors will provide good support and lots of libraries, the Free implementations often lack this. Many Lisp programmers use the commercial Lisps and have the features they want; if not they ask/pay the vendor to implement them. Another issue is that Common Lisp is not Unix-centric, unlike *ahem* most popular languages today. CL was designed to be workable in any environment, so the designers could not take shortcuts with things like pathnames, executable formats, system libraries, or other system-dependent issues. After all; Common Lisp was conceived in the era of the Lisp Machine. Unix was just another OS in the vast array. Finally, it is unfair to compare the Common Lisp standard against a single-implementation language such as Perl. Standards cost $$$$$ and require a great deal of effort and responsibility. If a Common Lisp implementation does not comply with the standard then it is at fault. But with Perl, whatever Larry Wall does goes. Even if it breaks all your code; too bad.
Some interesting sites with regard to libraries:
(Back to the OP's topic) Franz's Success Stories has plenty of examples of Lisp applications. Franz develops Allegro Common Lisp, a popular commercial CL.
Speed can range anywhere from what you say, to
.ENTRY FIXNUM-ADD(a b) ; (FUNCTION (FIXNUM FIXNUM) FIXNUM)
worse, to better than C. It all depends on
how well you write your code, and how good the
compiler is.
As for far from the machine? Uh, ok...:
CMU Common Lisp release x86-linux 3.0.4 18c+ 17 November 2001 build 2828
Loaded subsystems:
Python 1.0, target Intel x86
CLOS based on PCL version: September 16 92 PCL (f)
* (defun fixnum-add (a b)
(declare (type fixnum a b)
(optimize (speed 3) (safety 0)))
(the fixnum
(+ a b)))
FIXNUM-ADD
* (compile 'fixnum-add)
Compiling LAMBDA (A B):
Compiling Top-Level Form:
FIXNUM-ADD
NIL
NIL
* (disassemble 'fixnum-add)
48135B30:
48: POP DWORD PTR [EBP-8]
4B: LEA ESP, [EBP-32]
4E: ADD EDX, EDI ; No-arg-parsing entry point
50: MOV ECX, [EBP-8]
53: MOV EAX, [EBP-4]
56: ADD ECX, 2
59: MOV ESP, EBP
5B: MOV EBP, EAX
5D: JMP ECX
* (describe 'fixnum-add)
FIXNUM-ADD is an internal symbol in the COMMON-LISP-USER package.
Function: #<Function FIXNUM-ADD {480AD151}>
Function arguments:
(a b)
Its defined argument types are:
(FIXNUM FIXNUM)
Its result type is:
FIXNUM
* (fixnum-add 3 4)
7
* (describe 'unwind-protect)
UNWIND-PROTECT is an external symbol in the COMMON-LISP package.
Special form documentation:
Unwind-Protect Protected Cleanup*
Evaluate the form Protected, returning its values. The cleanup forms are
evaluated whenever the dynamic scope of the Protected form is exited (either
due to normal completion or a non-local exit such as THROW).
More information can be obtained from the Hyperspec
If you only use 10% of the features, you can only complain about 10% of the bugs...
May I say that I have finally found a car that is UGLIER than the PT Cruiser. Blech! When will car manufacturers get a clue!?
cCLan
mod_lisp and other Lisp WWW packages
I personally use IMHO with mod_webapp to write web applications for work. People write similar things in Java, but Lisp is a far more suitable language due to the interactive runtime compiler and introspective capabilities. I find CLOS to be a better, more flexible object system for these tasks than the Java/C++ model as well. Multi-method dispatch, multiple-inheritance, call-next-method, :around methods, and even some Meta-Object Protocol I have used in my programs. And I nearly forgot the really neat HTML macros that let you write out HTML in s-expressions. It's much less clunky writing HTML in Lisp than HTML as HTML, especially in Emacs.
I do believe they have a quote for this: "Those who do not learn from history are bound to repeat it." Which has also been stated as "Those who do not learn Lisp are bound to reinvent it." Witness Python and Ruby.
Actually the question should be: Do we really need another C compiler? Besides the fact that C is a poor language to optimize (weak typing, crappy calling conventions, broken arrays, you name it), it's about as close to assembly as a "high level" language gets and assembly is not a very good way to write quick and easily maintained code. Better to work on smarter compilers for languages that allow one to work on a higher level of abstraction. Projects such as CMUCL, SBCL, and OCaML could always use some help.
of hack on top of hack on top of hack....
Will these wonders never cease?
I seem to recall this very document being noticed by the "Slashdot crowd" at least twice previously. Every so often it gets reposted and apparently people have short enough memories that they don't realize it's the same document.
This looks like a clever assortment of levers and pulleys to allow a small amount of force to move a heavy object. Such machines are nothing strange; my question is, and I was unable to find a reason, why do you need a kite? Why not some people (they had plenty of slaves, no?) pull on the rope instead?
LISP
Scheme
Haskell
Dylan
Eiffel etc..
You're right, C and C++ are awful languages. C has carved out a niche for itself as a "higher-level" assembly language. C++, on the other hand, I just cannot see very much reason for. It is a language shoehorned into the retrictive C syntax that was designed (or not designed, really) for systems programming, and to work around the flaws they had to implement all sorts of nasty things. It forces you to worry about memory management, which defeats the point of a higher-level language (which lets you reason about the logical structure of your program rather than the nitty gritty).
What I'd like to say about CSS is that it's headed in the opposite direction from just about every other language out there. You see languages like Python and Ruby, slowly they are approaching the abilities of LISP, moving away from Fortran and Algol. CSS seems to me to be a step backwards, and will probably flop as a result. (But then again, look at the popularity of Perl. I guess there's a lot of masochists out there).
I think I should point out that while Python and Ruby approach LISP, they won't ever be LISP. The critical difference is in the representation of the programs. LISP programs are data. Some have said that if you removed all the parentheses from a properly tabbed LISP program, it would resemble a Python program. This is true, to an extent (never mind the lexical scoping rules and such), but the parentheses are not there just for show. LISP programs are data, and the parentheses give structure to that data at a higher level than ASCII characters: symbols and lists. And you can manipulate that structure with ordinary data-operations. Not to mention, LISP has had native-code compilers for 40 years, so it's better than just a scripting language. (see Successful LISP for further elaboration on these topics)
Which brings me back to your first point: the C preprocessor. I'm sorry to disillusion you, but the C preprocessor is a pitiful thing compared to the LISP macro facility. And it doesn't take too much extrapolation to figure out why.
It's hard to see the point of a scripting language that lacks so much compared to something like Python or Ruby, or even LISP.
ML's cool and all, but it doesn't have macros. Nor does it have s-expressions. Therefore it's not anywhere as powerful as LISP is in this area.
This is precisely the movie I've been trying to make work in my DVD player for quite some time now. I always get these scrambled green things and a SIGSEGV. So far, no cow. Here's to another attempt.
Last time I was writing programs in OCaML, my computer hardware crashed and was out of commission for several weeks. I've been too busy in the time interval to do any more, unfortunately. ;)
According to a good friend, OCaML does not have function polymorphism (such as 'defmethod' in Lisp) but it can be achieved through various hacks.
If you really want to write your own syntaxes nothing compares to the Lisp macro facility, (my friend wants to be able to infixify functions in OCaML, like in SML, but I think that's just a waste of time
All good Lisp compilers can infer types at compile-time, just like the OCaML compiler, and you can even specify static types and alter the amount of optimizing a compiler will do. Not only can you specify static types, but you can specify ranges as well! For example: (the (integer 0 100) x) specifies that x must be an integer from 0 to 100.
Pattern matching is an interesting feature, but its not that hard to write a condition to check for a cons and then do something. Recursive types are also interesting, I need to experiment more with those.