High-level languages like Ruby may contain lossy abstractions that obscure the low-level workings of the machine, but Lisp is another lossy abstraction that has the potential to obscure the high-level, abstruse workings of our own minds. Both of these abstractions can be valuable, but neither is without its shortcomings.
Sometimes ambiguity can be free, allowing indifference to how the machine works, without obscuring it at all. A good example is classical Hindley-Milner type inference (the algorithm that adds type annotations to plain System F code): it is fairly easy to construct oddball statements where annotating the types is undecidable or would cause resource exhaustion. But it turns out that for the known examples, it would be either impossible to decide the types in any form, or it would take O(c^n) bytes to enumerate the annotations.
So effectively there is no downside to the ambiguity -- the ambiguous statements are already infeasible for other reasons. Everybody Wins!
Intriguing. I'm not really convinced by your example though. In the spirit of conciseness is power[1], can you provide a short program that should be formally expressible in a good enough language, but isn't concisely in Lisp?
Or maybe your definition of low-level is different from mine?
[1] That's the PG version, of course.
My only problem with Lisp is that it's exactly the sum of its parts - no more, no less. Everything decomposes into self-similar pieces, which decompose into other pieces, and on and on, turtles almost all the way down. This is wonderfully elegant, but also feels like it precludes creating something which is more than the sum of its parts. This may not seem like a problem to a lot of people, or just sound like self-important nonsense, but the thing I enjoy most about programming is the tangible sense of gestalt you get when you've been working on a codebase for long enough. For me, Lisp doesn't provide that.
Yeah, I completely agree. I was going to write about it, but then figured it wasn't relevant to the question.
I'd love to discuss these old PG essays one day.
I am pretty new to programming, which means that I'm not stuck in conventions about how code syntax is supposed to be. On this background I find lisp pretty easy exactly because the syntax is so simple.
To me lisp is like chess: It's easy to grasp the basic rules, but hard to become a master.
1. So many parentheses!
2. You made a mistake right here.
Also, you might like this presentation, "The Swine Before Perl" by Shriram Krishnamurthi (of PLT). It's a great thing to show people who wonder how you could think Lisp has a good syntax: http://www.cs.brown.edu/~sk/Publications/Talks/SwineBeforePe...
(Also: SK's book is great.)
The two comparing s-expressions ("ugly, evil, and an insidious plot hatched by misbegotten academics") and XML ("a hip, cool, great new idea") I found to be particularly brilliant.
They force an inappropriate fundamental data type on everything, and are only of benefit if you want to fiddle with the insides of extant functions.
Use composition like a real FPer. Learn that there's so much more to data than lists + atoms.
Please explain.
(And I know composition, etc. I also use Haskell and Forth.)
'(GRAPH-EDGE <source-vertex> <target-vertex>)
whereas in ML you would write
type edge = { source: Vertex.t; target: Vertex.t }
which is not a list, but an entirely different representation. In Common Lisp the representation could of course be a CLOS object or a DEFSTRUCT (I think, my CL-fu is definitely not that good).
As for the composition, lisps are lacking (nice) currying which is one of the basic building blocks when constructing combinator-libraries.
There is something nice about a language (lisp) that doesn't look like anything else, in an artistic sense (not sure if that counts for much).
I think when most people complain about the parens, they are really complaining about the endless ))))))) at the end of an expression.
Meanwhile, we have no "dangling else" problem. Also, we have no need to memorize C's 15 levels of operator precedence, so when you see an expression, you never have to puzzle over how the items are grouped. In simple cases of C expressions, of course, it's easy, but it can get complicated. See "Java Puzzlers" by Josh Bloch and Neal Gafter to see how C/Java-style syntax can get you into trouble and fool you. There are pros and cons to each approach (C/Java and Lisp). I've used all of them extensively, and I prefer the Lisp way.
Lisp does, not just because it is so hopelessly low-level (for FP), but also because once you're using s-exprs it's hard to restrain anyone from mogrifying functions.
In a suitable language like Haskell where all functions are composed, using functional composition for everything instead of low-level fiddling with "statements as data" makes a shit-ton of sense. In Haskell you can also use supercompilation to resolve as much of the graph as possible at run time. No need for macros.
Don't think that other language communities want the warts from your language, just because you are so enthusiastic about them.
There are further answers from the Haskell wiki here: http://haskell.org/haskellwiki/Haskell_in_practice
But they have not. This can be due to multiple reasons: their disadvantages outweigh the advantages or that the effort of getting them into the language simply drags so many other undesirable things with it. Perhaps the advantage of a macro is perceived to be so small compared to e.g., function composition and higher order functions, that it is left out of the language.
Until you have read a clear description (e.g. Seibel) or had some experience, it's hard to see what macros are really all about.
Lisp macros are extremely important, powerful, and beneficial. Space does not permit me to go into the full explanation; see Peter Siebel's book and the great lecture he gave at Google, available on the web.
Macros allowed us to add object-oriented programming to Common Lisp. CLOS (the Common Lisp Object System) fits in very smoothly into the Common Lisp language, with a nice, clear syntax and very powerful semantics. At work, we have built an object-relational mapping system that, similarly, would be impractical (ugly and verbose to the point of unusability) without macros.
Yes, it is extremely hard to add lisp-style macros to C or Java because they have no s-expression structure you can work on. And they do not want an s-expression structure because it is too alien for those programmers. Thus, they perceive that macros are not worth the effort.
I think macros are left out of so many languages because people do not know how to incorporate them while retaining other desirable properties of the language (type safety for instance).
Also, macros are not the only way to build ORM systems. Python does the same with metaclassing as an example. But we can agree on that trying to map it into a statically typed language with reflection/AOP as Java did is doomed to fail I think ;)
I am not trying to say that macros are useless. I am trying to say that some languages leave them out on purpose. Many problems on which macros look nice can be solved with a little extra thought on representation. But then again, many can not.
I see the discussion of macros/no-macros a bit like the discussion on static/dynamic typing. With static typing, we know we are leaving some valid programs outside the gates of the static world. But we think that this loss is negligible compared to the benefits a static check gives us. Yet, some people oppose this viewpoint and wants the valid programs as well, because they perceive the benefits of the static typing to the negligible. Both approaches are valid, but it currently looks like it is hard to get all of the cake in one munch.
Ruby and Javascript library authors use the metaprogramming capabilities of their respective languages in combination with XML or JSON or YAML data. Look at ruby on rails, or at jquery.
Startup idea: web-based language-specific IDE, with a simple interface for sharing/voting on macros between users.
Here's an example. Take, for example, this class declaration:
(defclass dog (animal)
((size :accessor dog-size)
(name :accessor dog-name :init-form "Fido")))
How do you make that into data? Easy. Just quote it: '(defclass dog (animal) ...)
Now take the equivalent in Java: public class Dog {
int size;
String name = "Fido";
}
How do you get that into data? Well, I suppose the best you could do without modifications to the core language is just put it in a string. But then to do something useful you'd have to do so much tedious string parsing it wouldn't be worth it. I suppose you could invent a special ParseTree class or something, and a quote operator, and etc etc, but that wouldn't be nearly as easy as Lisp makes it.What the previous poster was saying is that once other languages have a code representation that is easy to work with as data, and can manipulate that code as data at compile-time to produce complex macros, then Lisp might fade. (At least that's how I understood it, correct me if I'm wrong.)
1. Allow a factory for Class.
2. Make Method contain the full body contents as a list of statements, and give them a factory as well.
Then it's a matter of reasonable constructor syntax.
With lisp, there's no difficulty mapping:
int main(int x) {foo()}
to Method m = new Method(return:=new Type(int),
args := new ArgList(
new Arg(new Type(int),
new Name("x"))),
body := new Block(
.... I'm sure you get the point....The syntax tree is apparent from the syntax.
(+ 1 2 (* 3 4))
Maps to: '(+ 1 2 (* 3 4))You can do things with the C preprocessor at compile time, it's just completely unaware of C, which really cripples it. The Lisp preprocessor (its macro system) is also running Lisp, and can easily process itself.
On the other side, you have any language with type theory governing the language design: haskell, ML, etc. These have long since gobbled up most people interested in type theory and even these are loosing out to the new batch of languages with richer type zoos.
Lisp is not a failure and it has had more influence than people think. However, I think Lisp has played its major part like IBM has played theirs.