Lisp: A Cult I Almost Joined (2005)
fluff.info
fluff.info
This is true of some programming, but not all. If I need to do some quick data munging, or build a CRUD application, lisp may not provide any benefits over another language in which I am equally skilled. But if I am programming in a complicated domain or doing exploratory work, I would rather be using lisp than any other language.
Sure. One thing about that is that the DRY principle -- and the expanded form, "don't repeat anyone, ever" -- has been a popular mantra throughout the programming community for a while (and even before that particular form, emphasis on reusable code was common), and Clojure has really come into its own in the time when that that philosophy has been strong.
One of the great things about macros is that they enable reusable solutions to broader problems than you can effectively address in library code in many languages; a corollary of which is that most programming in a language with macros should need neither to define new macros nor to use the repetitive boilerplate code that macros enable reusable alternatives to.
In case anybody else wondered about this: Neil's Armstrong purported conversion is a hoax that has its origins in an Indonesian pop song from the 80s (Indonesia is a major muslim country). [1]
> If such jokes reliably meet with stifling social disapproval, it's a cult.
An interesting definition I totally disagree with. It's the social disapproval that turned any of us into geeks, and guess what - I personally like it that way. Society approves mostly things that are pointless or boring anyway. An example: why do you think HN guidelines advocate against posting mainstream news?
Lisp may have been "mind blowing" before untyped scripting languages were a dime a dozen, but these days the only thing mind-blowing about it is that people still use it when there are much better alternatives.
Lisp is often referred to as a "functional" language but that has always seemed odd to me. Side effects are first class, and some dialects (like scheme and common lisp) are quite procedural. In fact the "ultimate" papers cite Algol as an inspiration. It is in no way a functional language in the sense that that term is used with, say, Haskell, Erlang or Prolog.
I do find Lisp the most expressive language I have ever used (and I wrote a LOT of code in it in the 1980s, 100s of KLoC over the years) but there are other languages I do use from time to time when their own particular strengths. For instance, string handling can be a bit roundabout in most Lisps. shrug.
Whatever you have used, it can't be Common Lisp, since Common Lisp is a multi-paradigm language with imperative, object-oriented and functional elements blended together.
Consider this code snippet:
(defparameter *persons* '((john 15) (maria 12) (agnes 20)))
(defparameter *number-of-persons* 0)
(defun count-persons (persons)
(dolist (person persons)
(incf *number-of-persons*))
(format t "~%The number of persons is ~a."
*number-of-persons*))
What do we see: * mutable variables
* procedures with side effects
* imperative loop with DOTIMES
* imperative setting of varibles
* sequences of imperative statements
Doesn't look like one is limited to 'functional style' in Common Lisp...There are definitely toy languages in the Lisp family (after all, there's quite a lot of lisps), but it pretty ridiculous to call Lisp a toy language.
> Interesting for it's unique approach to structuring code, but ultimately designed for a certain kind of mathematical elegance over practical functionality.
Most that I've read on the history of Lisp seems to show more of a preference for pragmatism than theoretical elegance.
> It grew especially popular with ai researchers, because they were searching for beautiful answers to the messy problem of intelligence
It grew especially popular with AI researchers because it was designed specifically to address needs in AI research.
> And it grew fans here and there for certain low-performance applications because it was one of the first languages with productivity enhancing features like garbage collection.
Lisps breadth and depth of production use has been considerably more than "here and there" and "certain low-performance applications".
> Lisp may have been "mind blowing" before untyped scripting languages were a dime a dozen
Being an untyped scripting language isn't the thing that is generally considered "mind blowing" about lisp, its the flexibility that comes from the combination of its minimal syntax, the macro system, and its homoiconic nature making code and data isomorphic.
One disagreement I have is Lisp is definitely not designed for high performance. Any competent C programmer would find the suggestion laughable. There's a write up for Orbitz somewhere that details many of the problems they had with basic stuff.
Second, less syntax just means messier code. Parentheses everywhere doesn't make a language good. Just harder to read. The "macro system" which refers to the ability to perform arbitrary functions on arbitrary data, is not unique to lisp. And in general, usually obfuscates code and makes debugging harder.
Code is data and data is code everywhere(it's all just bits and bytes after all). I would classify "its homoiconic nature making code and data isomorphic" to mean there's less syntax. Everything that you can do with macro's and Lisps's homogeneous syntax is achievable with similar constructs in other languages. The fact that the syntax is "homiconic and data isomorphic" is elegant, but in practice just confusing imo. Programming languages where data and functions are delineated by design have clearer structure and organization. Additionally they allow the compiler or interpreter to optimize by design. In the rare case it's useful to have a function become a data argument, there are usually accommodations in the language to do so.
These are just my opinions though man. You keep on using whatever programming language makes you happy.
There's a small DSL (domain specific language) to learn and then you get to write HTML in completely legal data structures where the entire language is at your fingertips.
Also, a simpler example: https://github.com/clojure-cookbook/clojure-cookbook/blob/ma...
Obviously it isn't any closer to modern hardware than C, but as far from the hardware as the high-level parts are, the low-level parts are pretty reasonably close.
Which puts it into similar regions as Java, Go or D.
Unoptimized Lisp code can be a lot slower, but it then supports a bunch of interesting dynamic behavior.
The main approach of better performing Lisp systems is to provide a wide variety of programming styles and a lot of flexibility, while being at the same time fast enough, so that not much software needs to be written in C or assembler. For example in a large CAD system it is possible to write much of the code in Lisp - in a space where such an application has to compete with systems written in C and especially C++. Depending on the quality of the Lisp implementation, the C/C++ part gets larger or smaller.
For example one of PTC's Creo CAD systems is written mostly in Lisp - a bit more than 6 million lines of Lisp code was reported a few years back.
In most versions of Common Lisp you can see the exactly assembler output of your function, allowing you to optimise your code at any level you want. Like other people mentioned, you can add type declarations to ensure that the correct machine types are used, and you even have goto. What specific aspects of Lisp are you saying prevents optimisation? Especially given that Lisp has more low-level control than most other languages.
A competent programmer, C programmer or not, would realize that performance is far more a matter of how you write your programs than what language you write them in; as the saying goes, "You can write FORTRAN in any language."
Now, the original LISP was not designed for high performance, to my knowledge. Later vendor-specific Lisps, like those found on the Lisp machines, were, because they had to be. Modern Lisps like Scheme and Common Lisp capitalize on the designs and technologies of those Lisps. For example, SBCL contains a very powerful high-level optimizing compiler that is capable of folding common code patterns down to efficient, often statically-typed machine code; that compiler dates back to the 'eighties when it was part of CMUCL.
Anecdotally, I recently ported a C implementation of introsort to Common Lisp. After adding type declarations, SBCL produced code about that took about 50% longer to run than GCC's code. The generated machine code used scalar integers, immediate-element arrays, and no runtime generic function dispatch. The comparative slowness was a result of the fact that SBCL's assembly-level optimization (or what little it has) is much weaker than GCC's, not of the fact that the code was written in Lisp.
>less syntax just means messier code
Lisp doesn't really have less syntax than other languages; it has more regular syntax. Forms like LET still have their own syntaxes beyond the lexical syntax of lists. Now, seventeen levels of infix operator precedence, that makes code messy.
>Parentheses everywhere doesn't make a language good. Just harder to read
Parentheses don't make Lisp hard to read. Being unfamiliar with that style of code layout makes Lisp hard to read. Once you're accustomed to it, the parentheses become mostly background noise, much like C's semicolons or many languages' "$s." Indentation is far more important, again just like in C. Lisp has the advantage that properly laid-out code clearly visually reflects the evaluation hierarchy, which is more than can be said for a lot of infix code, especially when dealing with complex arithmetical expressions.
>The "macro system" which refers to the ability to perform arbitrary functions on arbitrary data, is not unique to lisp.
That is not at all what Lisp's macro system does, and while there are other languages which have similar macro systems to Lisp's, they're at least as niche.
>And in general, usually obfuscates code and makes debugging harder.
Macros, when used correctly, make code more clear, not less. In fact, I've seen this argument made about a lot of different features in a lot of different languages, and it seems to me that what it usually means is, "I don't really understand what that feature is designed for." It's like claiming operator overloading is bad because it lets you define "+" to do division, even though you can just as easily write a function named "add" that does division.
>Everything that you can do with macro's and Lisps's homogeneous syntax is achievable with similar constructs in other languages
I can write a Lisp macro named DEFINE-ENUM that essentially does the same as C's enum, but also establishes a mapping from enumeration values to names; then, I could do
CL-USER> (define-enum color
(red 7)
(blue 23)
(purple 30))
COLOR
CL-USER> purple
30
CL-USER> (enum-name 'color 30)
PURPLE
How would you do that in C? It may be doable, but certainly not both general and easy. You're wading into the Turing tar-pit here.>Programming languages where data and functions are delineated by design have clearer structure and organization
Lisp delineates functions from other data (on that note, you described Lisp as "untyped." Lisp is in fact strongly typed). It lets you treat code as data if you like, but again the structure and organization of a program is a matter of how you write it, not what language you use. It's true, though, that Lisp lets you use (sometimes radically) different organizational structures than languages like Algol and C, but again those structures are unclear mostly because they're unfamiliar, not because they're inherently convoluted.
>Additionally they allow the compiler or interpreter to optimize by design
Lisp gives the compiler more room to optimize than a language like C; the tradeoff is that you don't have a human optimizing the difference as a matter of course (e.g., choosing a concrete integer type). This can sometimes be a good thing, and sometimes it isn't.
>In the rare case it's useful to have a function become a data argument, there are usually accommodations in the language to do so
It's actually very often useful if you have a way of writing generic algorithms; this is why "functors" are common in C++ (especially with the advent of lambda expressions), but not so much in C.
No one said it was. The issue you raised before was theoretical elegance vs. practical functionality. Practical functionality is much broader than "high performance".
> Second, less syntax just means messier code. Parentheses everywhere doesn't make a language good. Just harder to read.
Maybe on the parens, though I think that's more a result of expectations set by people starting in other PLs.
I've often thought that a layout-based system similar to that used in, e.g., Haskell could produce a cleaner-looking Lisp that would mitigate this popular complaint, without any substantive change to the language.
> The "macro system" which refers to the ability to perform arbitrary functions on arbitrary data, is not unique to lisp.
No, that's not what the macro system is. The macro system is the in-language facilitate to manipulate the the syntax tree of the program. Very few non-lisp languages have a similar feature, though some have techniques of approximating some of what the lisp macros can do.
Thus it was expected that Common Lisp was to be implemented on supercomputers. For example Allegro CL had a port to one of the early Cray systems.
To support the goal of 'efficiency' Common Lisp provides: type declarations, inline declarations, compiler policy settings, compiler macros, a 'file compiler', compile-time macros, compiler macros, a disassembler, a timing macro, low-level type-specific functions, low level control structures like gotos, ...
One thing it lacked was 'TCO', tail call optimization, but that was something many implementations of CL provided.
A few compilers were written to support this goal of efficiency. For example CMUCL (which provided type inference and 'block compilation') and Lucid Common Lisp. Lucid CL had two compilers: one for interactive use and one for application delivery. The latter did much more optimizations and also supported 'block compilation' (the compiler optimizes the code not only inside a file scope, but also on a collection of files).
Other commercial compilers like Allegro CL and LispWorks were improving efficiency over time, based on customer requests. Customers had written applications and they wanted to improve their speed: numeric computations, object and record slot access, garbage collection, ... were examples. Thus not also the compiler, but also the runtime had to be efficient.
CLtL (1984) provided the initial definition of Common Lisp; Lisp had already been around for nearly 30 years, though, and there are lots of Lisps around whose only influence (if any) from Common Lisp is indirect.
Lisp is not a language. It is a family of languages.
Thought that was obvious.
Maybe although looking at benchmarksgame Clojure doesn't do to bad. Roughly 2-3 times slower than C, C++, On a par with c#, go, ocaml, scala and maybe Java much faster than Python, PHP, Ruby and Erlang.
http://benchmarksgame.alioth.debian.org/u64q/compare.php?lan...