10 ms·
That's it, in a nutshell. The macro facility is what differentiates Lisp from other dynamic languages that have, seemingly, all of the same attributes--dynamic/
by Todd 19y ago
That's it, in a nutshell. The macro facility is what differentiates Lisp from other dynamic languages that have, seemingly, all of the same attributes--dynamic/lexical scope, closures, etc.
They allow you to write a true DSL. Paul Graham pretty much wrote the book on the subject (On Lisp) which he graciously offers as a free download since it's out of print.
- pg 19y agoAs a data point, in the source code of Arc and its libraries + the web server + News.YC + all of YC's internal applications, there are 738 calls to def (= CL defun) and 187 calls to mac (= CL defmacro). This isn't a complete list, because there are other defining operators, but it gives you an idea how large a role macros play in a typical Lisp application. If you measured by uses of each type of operator, the role of macros would be even larger. You often write a function that you only call once, but you wouldn't do that with a macro. Here's the last piece of code I wrote. I wrote it because I was curious to see what colors users had chosen for the top bar. (defopa topcolors req (minipage "Topcolors" (tab (each user (sort (compare > [karma _]) (keep [aand (uvar _ topcolor) (isnt it (hexrep orange))] (keys profs*))) (tr (td (link user (user-url user))) (tdcolor (hex>color (uvar user topcolor)) (hspace 30))))))) There are 10 macros used here: defopa, minipage, tab, each, karma, aand, uvar, tr, td, tdcolor. Actually it's a hack that karma is a macro. I wanted it to be settable and was too lazy to define a setter, so I just defined it as a macro. It should be a function, and I should be able to say just (compare > karma).
- Tichy 19y agoI thought that Arc is written in Scheme, not in Common Lisp? Are Scheme Macros equally powerful? Edit: OK, perhaps Arc is written in Scheme, but Arc itself features CL like macros, that would explain it ;-)
- eru 19y agoAs far as I know Arc is written on top of MzScheme. Besides its 'clean' macros - MzScheme supports CL like macros, too. But your explanation could be correct as well.
- pg 19y agoArc is written in Scheme in the sense that it compiles into Scheme, and uses the Scheme read, numbers, etc. But Arc macros are not Scheme macros.
- apgwoz 19y agoScheme also has "CL" like macros that are hygienic. Scheme 48 for instance, supports explicit renaming macros and MIT has syntactic closures. However, most schemes have a library that adds your traditional defmacro style macros, CL users are likely to want, but there use is almost always discouraged.
- pg 19y agoI just entered this variant into the server's repl so everyone can see the range of choices: (defop topcolors req (minipage "Custom Colors" (tab (each c (dedup (map downcase (trues [uvar _ topcolor] (keys profs*)))) (tr (td c) (tdcolor (hex>color c) (hspace 30))))))) Defopa means only admins can use something, but since this is defined with defop, everyone can see this page: http://news.ycombinator.com/topcolors http://news.ycombinator.com/topcolors.
- Tichy 19y agoThat calls for the feature to enable color picking by clicking on the colors ;-)
- kirubakaran 19y agoNow you don't think pg's time would be better spent writing essays, do you? :-) http://news.ycombinator.com/item?id=97830 http://news.ycombinator.com/item?id=97830
- Tichy 19y agoJust trying to go with the flow ;-)
- sridharvembu 19y ago(before I begin: I am familiar with macros & DSLs, code generation, building a custom language layer and then write your app in that custom language and so on, and I buy into almost all of it) I am sure the code above is poetry for those deep into it, but for a person who is a bit rusty (or god forbid, new to the code base), this is basically indecipherable. Look at how many tokens are there in a line like (each c (dedup (map downcase (trues [uvar _ topcolor] (keys profs*)))) How many people can answer the question of which ones are macros, functions, simple identifiers and so on? In that particular example I am stumped at [uvar _ topcolor] and can't get past it. Yes, I have read Paul's thesis on Lisp code density (quick summary: each line is dense, but there is a lot less overall code so it evens out or better), but my counter would be that there is a density beyond which most mortal brains can't penetrate. Without intending to cause offense, I am going to say that this is tending to write-only code. Sure, the equivalent Ruby or Python (leave alone blubs like Java or C#) would be pages long, but I suspect that lower density leads to better understandability.
- icky 19y ago> and I should be able to say just (compare > karma). I suggest you implement a terse syntax for partial-apply. For my own pet lisps, I use {}. (You are welcome to steal it ;-) So {+ 1} would expand to (in scheme) something like (lambda rest (apply + `(1 ,@rest)). You could keep partial-applying arguments (do (= x {+ 1}) (= y {x 2}) then actually apply it with () (y 3 4 5) ; => 15 Your accumulator generator in Arc: (def foo (n) [++ n _]) Could be shortened to: (def foo (n) {++ n}) ; even terser than regular Arc! The only time you'd need _ is when you want to change the order of the arguments (e.g. you'd never need {+ _ 2}, but you might need {/ _ 3}, or even {/ _ _ _ 3} if you want to jam the first three arguments in front. This has some other interesting properties: - In a lisp-1 OR lisp-2, #'foo can be represented as {foo}. - Your karma macro can fit in there as (compare > {karma}) - With the _ variables, it might even be a general case of your [] syntax. - {} stands out visually. "Here be electric magic." - If you ever implement generic functions dispatched left-to-right, you can implement partial dispatch for partial application.