What's Special About Lisp?
kresimirbojcic.com
kresimirbojcic.com
That said the author missing an obvious thing here. They key with macros is that they allow you to alter syntax (not calculate values as many who try initially misunderstand them), and s-exps are essential to being able to do this (because they are effectively an abstract syntax tree).
I say this is obvious because the example itself demonstrates this. The lisp code in the end looks very much like the ruby. Being able to extend syntax means that if you like ruby you can make your lisp work more like it. Now try to reverse this example, make a ruby library that emulates a lisp style, I think you'd find it much more difficult, and expensive.
The other important thing to not forget is that this syntax transformation happens at compile time. One of the reasons that Ruby has a reputation for being slow is it has to keep track of a lot of metadata and all sorts of look-ups to do a lot of the metaprogramming (which is why people should make better use of it, you've already paid for it). In Common Lisp all this transformation is free during runtime. Think of a common issue with JavaScript: no implicit return. If Lisp did not have implicit return you could define a macro 'defr' which allowed you to define functions like you normally do, but always know they return a value. Instead you need to use CoffeeScript.
Finally people do still write plenty of Common Lisp, they're just a smaller community. Not long ago I wrote myself a very practical tool to process a specific file format, with it's own mini-dsl, an order of magnitude faster than similar libraries (albeit with intentionally less functionality) and all in 200 lines of Common Lisp.
(Edited: awkward English.)
Counterexample: macros in Dylan (http://www.opendylan.org/books/dpg/db_329.html).
It's certainly true that Lisp's super-simple syntax makes it much easier to have a powerful macro system. Dylan macros are like Scheme's hygienic macros, based on pattern-matching and not as flexible as CL's fully general code-generating macros -- but still pretty powerful. (And there's an unofficial procedural macro system too, which I haven't looked at but I understand gives you CL-like power without too much pain.)
Lisp programmers, when using Lisp for what it's best at, don't use libraries. There are no libraries for what they want to do, because what they're doing is obscure and/or hard.
Lisp is best at doing new things that have never been done before, because it's basically a language for writing libraries. As such, it prospers in unpopular fields.*
This makes it hard for lisp evangelists to be taken seriously. If you're to show someone a hard graphics problem written in lisp vs ruby, your reader has to understand graphics programming first. But calculating primes? Anyone can do that. Which example do you think will get more mindshare?
To summarize: Lisp is great at things you don't hear about.
* One reason Viaweb succeeded using Lisp for the web was because the web was still this exciting frontier and no one had really done anything with it yet. I'd go so far as to say that Viaweb wouldn't succeed today---they'd get trashed by the likes of Weebly, which is written in php for crying out loud.
Actually, "library" is probably the wrong word for reused Lisp code. A library is a public thing, an institution---and all that goes with it: slow to change, must be easy to understand, etc.
Instead of libraries, Lisp hackers have private collections. Like a messy desk, they are often supremely useful once you get the hang of it, but are inscrutable to others. Not exactly the best characteristics to get popular on github.
Certainly Github does not in anyway support your claim: https://github.com/languages/Clojure
But also its not that its great for writing libraries but that its great for writing libraries that extend the language.
The state allows parts of program to communicate through implicit information channel. One part of program could signal another to increment a variable by deleting a file. Or vice versa.
That's why I think Haskell is the best for libraries, Scala less so and Lisp even lesser, even taking into account macro system, code-as-data, etc.
That said, why not try Clojure? Best of both worlds, and then some.
But I'm still at the point in my career where people hire me rather than the other way around, and all the hand-waving I can do about "superiority of lambda calculus over the state machine" (okay, I'm more clear and practical than that) doesn't convince many.
Making Python or Scala talk to Oracle (for example) is so trivial you can write that bit of your program in no time at all, then get onto the interesting stuff. In Lisp, you have to spend significant time on this trivial stuff. So if you are writing a program on your own PC for your own use, then Lisp is fine. If you are programming anything that is going to run on existing infrastructure or interoperate with other programs, it's very difficult to justify the additional effort of using Lisp.
And I know a bit about this: I wrote Oracle bindings for OCaml! It was fun, sure, but can I justify it when there are already Python bindings? Hmm.
Remember: Lisp is a family, not a language.
The best counterexample to your claim is: http://clojure.org/
I'd argue even CL covers a lot vs your claim (but please don't make it my arguement, focus on Clojure) with QuickLisp: http://www.quicklisp.org/beta/
I've created 3 libraries that I think would be exceedingly difficult, excruciating, or impossible to write with the performance and the level of control over syntax in anything but a very good Lisp:
http://github.com/clojure/core.logic, efficient embedded Prolog in 1K LOC
http://github.com/swannodette/match, in progress implementation of a state-of-the-art OCaml pattern matching algorithm
http://github.com/swannodette/delimc, delimited continuations
"homoiconicity": the property of a language whereby code written in said language is stored, in a natural and immediate fashion, as a data structure of the same language
What this means for Lisp is that if you want to manipulate Lisp code, you aren't dealing with some crazy complex AST: you can actually /see/ how the code is parsed by looking at the code itself, as the code is actually typed using the serialization format for the primary data structure of the language: S-expressions.
So, you aren't just creating a little "DSL" by using some built-in syntax tricks like "implicit last argument block", but instead are able to write code that modifies code and generates code as easily as if you were writing the original code in the first place: the comparison to Ruby is therefore fundamentally flawed.
(Finally, as an unrelated bonus: the parser for Lisp is also written in Lisp and available during the execution of Lisp, so you can have code that modifies and extends the parser itself allowing you to fundamentally alter the syntax to, for example, look like Ruby; this mechanism is called "reader macros", for the record.)
> instead are able to write code that modifies code and generates code as easily as if you were writing the original code in the first place
Is this often done? I know it is conceptually possible with the advantage being that the same functions used to manipulate lists and data are available for this task, but I got the impression that not many people actually do this? For instance...
http://stackoverflow.com/questions/6480053/modifying-functio...
Also because you can modify the syntax with them they can really clean and clear up your code.
Statements like "You can easily do this is Ruby" hint that author understood exactly nothing and focused on some random uninteresting example code while missing big picture.
Does Ruby have COND?
If it doesn't, can one implement it using existing Ruby constructs?
If it does, can one implement it using existing Ruby constructs except COND?
def COND(*args)
args.each_slice(2){ |s| return s[1].call if s[0].call }
end
COND(lambda{ false }, lambda{ "not this"}, lambda{ true }, lambda{ "this" })
(not a lisper, though, so I might be missing something).This. The ability to easily reason about the code and manipulate it because its syntax is simple and predictable is the big deal to me.
I think this is analog to switching from Roman to Arabic numerals. The syntax is regular. No matter how big the number is the rules are the same. There are no exceptions. Hence doing calculations with the former is a lot clumsier than with the latter.
That's the ideal scenario at least. I do realize that math might not be as simple as it could be, but I'm not really qualified to argue about that. But what if we were still using Roman numerals today? Would we be at the level of understanding we are at right now? It seems to me that it's more or less the same thing when you start understanding Lisp and why it is the way it is.
This is just too big of a tradeoff to be ignored. In my experience choosing the simple and regular solutions paves the way to progress, in which useful things that look trivial now would be rightly discarded or would be viewed as too complex if our mental model were grounded on the previous clumsy framework.
Now, I'm not saying "just drop all your clumsy languages right now, because today we have a better idea, and start using Lisp". I certainly don't do that. I don't even work with Lisp. But my point is that not realizing that Lisp has some properties that make it special is perhaps hindering yourself of being able to see that some things can be a lot simpler than you thought they could be.
Consider https://gist.github.com/1119534, which demonstrates a pattern-matching syntax that (at compile-time!) constructs a minimal traversal of the data structure to find a match. The only way to do this in a language without macros is to write your own compiler.
http://www.cs.brown.edu/~sk/Publications/Papers/Published/sk...
That doesn't make sense, because there's no way to twist it. It's more work and duplication. I want macros all the time in JavaScript and that is a pretty flexible and dynamic language.
Most of Lisp's other features are common now. Macros are still a big one but you don't need them every day. Lisp has powerful exception handling but I'd rather have Erlang style error handling and recovery.
Lisp's draw is waning but only because our languages are lispy in ways that really matter. We have dynamic, garbage collection languages with REPLs and built in high level data structures that are even better because we have native syntax for them. I don't want to keep track of N different kinds of assoc lists... and I really like Lisp.
Special variables, restarts and flexible reader are some of the basic features, that are not only uncommon, but, actually, unseen in any other language. Just to name a few.
Factor has a cool and flexible reader too but it's pretty far from mainstream.
For instance, I'd do (untested):
(defn prime? [x] (every? (fn [n] (not (zero? (mod x n))))
(range 2 (Math/sqrt x))))
(doseq (map pr (filter prime? (range 0 20))))
for the same effect. And I really was happy to write that. It makes sense.NB: I'd never put such code into production, and I think it should be a warning sign that a purported problem in a language/dialect be based around minimal experience regarding an example.
Now, the featured article picks a... not very good example, for this feature of the language. But that doesn't mean that metaprogramming is useless. Much of a (big) lisp program is building up a domain specific language out of macros, then solving the problem at hand with it. This is the biggest power of lisp, and also the biggest weakness--every lisp program is written in a different language.
In lisp you express your problem in macros, and then express your solution in the language you've built up.
As pg says: "In 1960, John McCarthy published a remarkable paper in which he did for programming something like what Euclid did for geometry. He showed how, given a handful of simple operators and a notation for functions, you can build a whole programming language. [...] It's worth understanding what McCarthy discovered [my emphasis], not just as a landmark in the history of computers, but as a model for what programming is tending to become in our own time. " http://www.paulgraham.com/rootsoflisp.html
Why does pg say McCarthy discovered Lisp, not invented it? I think because it's something of such simplicity that one can imagine others inventing the same thing. So if humans contacted intelligent aliens, it wouldn't surprise me if they had independently invented Lisp, just as it wouldn't surprise me if they'd invented prime numbers, or cartesian co-ordinates.
"Because coders DO NOT LIKE LISP. Most programmers find Lisp unpleasant and unnatural to use. They're not idiots, they're not ignorant, and they're not willfully choosing a less-powerful or less-efficient tool, they're choosing tools based on what makes them productive and happy."
The "profound enlightenment experience you will have when you finally get [functional programming]" [2] is a mystery that I've been trying to figure out, albeit slowly since the day only has 24h. I've gone through the Peepcode video on Clojure and I couldn't find an answer, and I didn't even feel attracted to the language, quite unlike my first Ruby experience.
Then the other day I watched Matz - creator of Ruby - talking about Ruby 2.0, and he used the word "happy" multiple times to explain how he wants developers to feel when using his language, and I thought of how brilliantly he's succeeded. I have now spent more time coding in Objective-C than any other language (iOS development), and every hour I code Objective-C I miss Ruby and how happy it makes me feel.
I find that happiness is highly overlooked in discussions about programming.
[1] http://discuss.joelonsoftware.com/default.asp?joel.3.371875....
[2] http://www.paulgraham.com/avg.html
(edit: formatting)
Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that. But it is nicer to ordinary people
Nitpick: the quote is not exactly about functional programming, it's about Lisp. Though Lisp is often used as a functional language, there are very lisp-ish features such as macros and the (lack of) syntax that you will not necessarily find in other functional languages.
That said, if you want to learn functional programming but are put off by Lisp's feel, you could try Haskell or OCaml or F#.
In any case, this is very much a question of discourse. For historical reasons Lisp (at least Common Lisp) seems to have this reputation of being associated with deadly serious people, or alternatively smug lisp weenies, while Ruby people talk about how happy it makes them feel all the time, even though there are plenty of people who clearly have fun with Lisp (even "crufty" "old" CL), and I'm sure many people would regard working with Ruby a chore. I mean, to each his own, I honestly can't imagine there's an objective scale on which CL (much less exciting new languages like Clojure) is "less fun" than Ruby. Things like homoiconicity, on the other, are objective criteria for comparing languages. There are plenty of reasons to like (say) Python better than (say) CL, but to say that homoiconicity or restarts or MOP are no big deal because if you try hard enough you can replicate 95% of that functionality in (say) Perl is a different question entirely.
That was pretty much my point. That maybe the solution to the mystery of the "profound enlightenment experience" around Lisp is that it makes some very happy, but not me.
Have you looked at "The Joy of Clojure"?
I haven't, I'll look into it, thanks. I haven't given up on solving that mystery yet.
Like all other languages, programming languages are also just that, languages - tools to express your thoughts. To me and many others Common Lisp reduces the friction between those thoughts and written description of them. It is so much more to this language than just its syntax and politics. It is joy to develop in thanks to SLIME, it almost never gets in your way, it performs, it has wisdom of half a century and people who possess it. Yes, it is far from perfect, but then again - there is no perfect language! and even if there was one it would sound like those studio processed pop-star voices rather than perfection to me, because it would still superimpose its perfection over you own views.
In other words, please don't judge the language by how you can pronounce "how can I get to the city centre", it sounds similar in most.
Now all this spoken/written language comparison might sound weird to you, but to me it makes perfect sense, because programming to me is nothing but a dialogue between me, computer and the future version of me reading the source. And I like the language which allows me to do this on my terms, rather than that of Guido, Matz or whoever. And to me Common Lisp is pretty close to that.
P.S. Just as a side note, folks on #lisp and #sbcl are one of the most pragmatic and intelligent people I have ever seen, I learned more from their discussions than by reading a couple of books. To any of you reading, rock on Lispers ;)
Well, macros for one didn't exist in Lisp in 1958.
In general, Lisp doesn't seem special anymore because (1) language implementers have taken Lisp's most important lessons and applied them to their own languages and (2) said languages have become relatively popular.
A lot's happened since "Beating the Averages". http://www.paulgraham.com/avg.html
I don't think like other language designers often. So I like a flexible language.
(defun sum-of-prefixes (tup)
(let ((sonssf 0))
(loop for n in tup
do (setf sonssf (+ sonssf n))
collect sonssf)))
The variable 'sonssf' is an acronym for "sum of numbers seen so far;" this function creates a list of sums of all numbers it visits as it traverses the input list.ie:
(sum-of-prefixes '(1 1 1))
=> (1, 2, 3)
(sum-of-prefixes '(1 2 3 4 5))
=> (1, 3, 6, 10, 15)
It's a simple bit of code that I go into in more detail with an example in Python and Scheme: http://agentultra.com/?p=670The reason why I think Lisp is a great language is that I haven't yet needed to use any "patterns" in any of my (admittedly small) projects. Patterns, IMO, are boilerplate code to work around the limitations of a language. I haven't encountered a need for that in Lisp yet. It's a good sign to me.
I also have dynamically scoped variables, generic functions, parametric dispatch (or multimethods or whatever you call it), macros, and a very powerful OO system if I need it. Best of all is that all of it is unified by a small amount of syntax, backed by a small set of axioms, and surrounded by a wonderful (but small) community.
edit: Fixed the example output
http://www.randomhacks.net/articles/2005/12/03/why-ruby-is-a...
Ruby is a denser functional language than LISP. This is just not true! Sure sometimes you have syntax suger in Ruby that makes something smaller but othertimes you don't in lisp I can always make everything smaller with macros. I would bet that Ruby is not shorter for most programmes.
His hole argument is based around that in lisp you have wo write (lambda ....) and in Ruby you don't.
Ruby gives you about 80% of what you want from macros Ruby may give you some of the power but there is a lot you cant do in ruby and its much, much harder to do those things.
Ruby’s libraries, community, and momentum are good Thats nice but has nothing to do with being lisp.
Not saying anthing against ruby but this article is just very strange.
I ask the question because you can achieve the same results in most dynamic languages by grabbing the string representation of a function, run it through a parser, modify the resulting AST and then regenerating the function string before passing to an eval (CoffeeScript being a good example of this approach). Sure, it's messier than in Lisp, but in return for the messiness of macros, you get much easier to read syntax in most of your code. Is the use of macros really such a big part of Lisp programs that it justifies the lack of syntax everywhere else?
user=> (macroexpand '(or true false))
(let* [or__3470__auto__ true] (if or__3470__auto__ or__3470__auto__ (clojure.core/or false)))
Also, I don't think that lisp "syntax" is unreadable, on the contrary.
Your example of meta programming is very very messy and putting eval everywhere would also be a security nightmare and if you do it this way you don't end up with nice syntax. <-- People don't really use this because of those reasons.
Macros are not messy to use they look like a normal function that meens often you don't even know or care if something is implmented in a macro or a function.
The other big part of the macros look like language build ins for example in a REST-Framework you would have something like 'defresource'. The auther of the framework can give you the best syntax to discribe what his library does. (Look on Stackoverflow for DSLs in Clojure)
Writting good macros your self is a little harder and can look wired because your just not used to code looking like this.
The USE of macros is a REALLY REALLY big part of every lisp programm because the HOLE language is build on macros. Almost everything that is normally build in the compiler is just a macro.
Secondly, Lisp macros are every bit as big a security risk as using eval... That is what the E in REPL stands for, after all. In both cases, if you are taking input from source code, and not from outside sources, there is no security risk.
Thirdly, yes, my example is messy. But it is still doable, and I just have a hard time believing that this kind of programming is a major percentage of the code of a Lisp program. To be clear on that comment, I can easily believe that you end up invoking macros a lot, but I don't believe that a large percentage of the code written for a project is actually macros. What percentage of code in a typical project is macros? And how many of those macros can be easily reproduced by using specialised syntax of a language such as ruby (optional parantheses, blocks, re-opening classes, method_missing, etc)?
This is an important point, because if you only have a few hundred lines of this stuff in a typical Lisp program, and it can be reproduced by using a parser in another (dynamic) language, then the advantage just isn't that big. For argument's sake, imagine having a module available in Javascript that provides the Jison parser along with the Javascript grammar, which just re-emits the original Javascript source. In addition, it has a nice API to allow you to modify the grammar (adding / modifying rules). So far so easy, this stuff already exists in CoffeeScript, go copy it from there. Now, having loaded such a module, is Lisp really in a much better position than this modified Javascript?
You think of macros as a kind of pay of for s-exp syntax. I have to say that even without macros I would think s-exp syntax is nicer. Sure in Ruby you can do alot when you play around with that suger stuff but this stuff often doesn't come free. See this blogpost for an example of what I mean: http://briancarper.net/blog/579/keyword-arguments-ruby-cloju...
Depending on what you do you are writting a lot of macros. In lisp the interface to a library is almost always in a DSL style witch makes them easy to use. See this list here: http://stackoverflow.com/questions/3968055/are-there-any-clo.... In your own Application your maybe not going to need them that often depending on what you do.
What you discribe is just a macrosystem. Having macros in a language with syntax is duable (look at Dylan or Plot) but you will find that getting everything nice and easy to use is much harder then you think. If CoffeeScript has a macrosystem great. I don't really know CoffeeScript well enought. Could you provide me with some nice examples of how people use this in CoffeeScript?
If I where you I would just learn enought lisp that you can trie it out yourself.
I'm hoping that if I keep at it with Haskell, that eventually I'll have my 'I get it' moment with it as I think I can learn a ton from when I get it, much like I did with Lisp and Smalltalk.
I've learned things from many different languages but the two I've learned the most from where Lisp and Smalltalk.
[1] Even though it's trivial I still adore this simple example:
guile> (define D derivative)
guile> (define f (literal-function 'f))
guile> (define f^2 (expt f 2))
guile> (pe ((D f^2) 't))
(* 2 (f t) ((D f) t))
Add in the little things like being able to have boolean-returning-functions ending with '?', Lisp is very free.