The last couple of weeks I've spent my days reading 'The joy of Clojure', Structure and Interpretation of Computer programs, lots of tutorials and documentation, playing around in the repl + experimenting with all kinds of frameworks and libs in clojure (eg. Om).
I've spent today implementing the brainfuck interpreter in Racket.
I can't explain it, it's like something is calling me - 'learn lisp. now.'.
Given the amount of Lisp code read/written and the relative novelty of it, I'm dreaming lisp code and the arguments to functions are actual physical things, which are then mapped, reduced, recursed or expanded.
Literally, I think I'm going crazy.
I can fluently write x-platform C++, Javascript/CoffeeScript, Objective-C, Java, Pascal, VB and everything in between.
But never have I experienced this kind of mental strain/obsession as I do now with lisp.
But.
Seems like I'm not alone! Given the amount of lisp news lately on HN, I fell like more and more people are going through what I'm going.
Seems like we here on HN follow a common mental pattern and suddenly everyone's talking/learning lisp.
As interesting as learning lisp is, this 'group preference' thing is even more interesting to observe.
LISP's also has a long history of popping up all over the place because they are extremely implementation-friendly (if you want to write a simple language; if you want to make things fast they get trickier, thought by no means impossible) given the simple syntax.
So you'll also find a lot of people (like me) who don't really like LISPy languages, but who still end up dabbling with related technologies occasionally (my very-slowly-in-progress Ruby compiler uses s-expression syntax (though no LISP semantics to speak of) to express a tiny language to implement some of the lower-level plumbing to bootstrap the Ruby core classes, for example)
That's why it's so valuable as a right of passage. If you've spent your career writing simple iterative imperative loops, suddenly you're a newb again with map/filter/reduce this, partial that, and recursion and lambdas and closures and finally after your 20th time staring, dazed at 3 measly lines of nested composed recursion - it all starts to flow, and boom, you have a new way of approaching every problem.
And even if you don't live in the lispy functional realm after that you'll always be better off for having crossed that threshold.
I still do C#/Javascript/Java/whatever in my day job, but LISP is just...sexy.
And for those that hate parens - Emacs paredit. Nuff said.
You begin thinking "naturally" in Lisp because there's no syntax to memorize, it's all data and / or semantics. You can literally write the code in your head. Languages I've used for years and years don't do this to me like Lisp does.
It also made me feel more confident about programming in other languages and not to get distracted by "fancy" syntax or features that are just warmed over scraps from the floor of Lisp's feast on the table.
At the time, although I could read the material, it seemed to require too much mentally to actually Get Things Done. I think it was a deep misunderstanding about how to structure a program that is independent of state.
Later, after playing with Scala, amongst other languages, I came to understand that state exists in functional programs. It's not conjured up out of nowhere, spontaneously brought into existence, but rather, it exists as data, and it is the job of the program to direct the flow of data appropriately - like a plumbing system, so to speak.
Since that statement occurs in a section about Racket languages, I should probably clarify. Arc isn't technically a Racket language—that is, it doesn't use any of Racket's facilities for defining new languages. It compiles to Racket (and so you're all using it right now), but has its own distinct implementation.
Historically, Arc wasn't built on top of Racket. I think pg may have started on Common Lisp, then went to Scheme 48, Mz Scheme, and so on. Probably the most accurate thing to say is that Arc was built in pg's head after years of thinking about Lisp. It doesn't have a particularly close relationship to any of those underlying platforms. Semantically it's closest to Common Lisp, but don't tell pg I said that.
As I allude there, Paul Graham’s writings about Lisp (mostly in Hackers & Painters) helped persuade me to explore Lisp languages. (Those writings have also persuaded many others.)
In particular, Arc's reliance on Racket persuaded me to take a serious look at Racket. So leaving aside quibbles about what “on top of” means — is Clojure not built “on top of” the JVM? Python “on top of” C? — Paul’s choice of Racket was influential in my choice too. (As it has been for many others.)
As for software being “built in [one’s] head,” that seems facially true of any software. The core thesis of “Beating the Averages” is that the tool you choose to get it out of your head and into the world matters. Having now had my own Lisp revelation, I not only buy Paul’s thesis, but I even think it could be strengthened: Lisp permits the implementation of a whole category of ideas that aren’t possible in other languages.
Moreover, Paul wrote that essay nearly 14 years ago. Since then, Lisps have gotten somewhat more popular (Clojure has led the pack). But as I say in the article, as a group, Lisps remain way behind the programming mainstream. So ultimately, my goal is not to evangelize for Racket and exclude other Lisps. I know Racket better because that’s what I use. But more people using all of them would be a great thing.
"I wish they had implemented Arc as a Racket module language since then you could actually develop in DRracket, debug, and make executables."
Have noticed quite a bit more buzz about Racket and Lisp very recently around here. It's always been something I mean to explore.
I'm already pretty good with Clojure, so can anyone who knows both languages well comment on the ups and downs of learning Racket after learning Clojure?
http://okmij.org/ftp/Scheme/xml.html
There is a Racket "package" (not quite a port) of SXML and SXSLT:
[0] https://www.gnu.org/software/kawa/Android-view-construction....
I think Pollen's biggest strength is that you can reprogram its markup -- as its documentation puts it, you can attach behavior to tags. I haven't taken much advantage of that yet, but you can do things like create a "TOC" tag that builds a table of contents by inspecting child documents and looking for h1 tags (or looking for, say, "chapter" tags, which you've defined to expand to "<h1 class='chapter'>"), or inspect the contents of paragraphs and subtly shift the first line margin to the left if the first character is a quote mark (which Butterick's Practical Typography does). You could replicate some of that with a template language that allows user-definable tags, but I don't think you could do all of it.
Its biggest weakness, at least for me, has been finding a pleasant workflow. Despite having a built-in web server it feels kind of clunky compared to other static site generators. You're largely on your own for writing a deployment script ("raco pollen clone" is not a valid substitute). The DrRacket IDE is virtually a requirement for Racket programming, but it sucks teabags for editing long prose documents; you'll likely find yourself working in one editor for Racket language files and another for Pollen source. This isn't necessarily a dealbreaker, but it's at the least annoying.
It's a very simple idea, really: you write your document and sprinkle racket s-expressions wherever you want. You can put your definitions at the top of your document, or in another file. You describe your templates in Racket also, because like Butterick says in his RacketCon video [2], "S-expressions and XML are the same thing". You can use tags that you haven't defined, they just get placed in the resulting HTML.
You still have to roll your own CSS and any JavaScript. As far as I can tell it doesn't help you out with things like keeping track of footnotes numbering or citations and such: you roll your own for things like this, Pollen is no LaTeX. This is partly why I say it's a really simple system. It makes a certain set of web authoring things simple, but it doesn't try to be a one-stop shop, which is excellent because this makes it a supremely flexible tool.
It also has some backend fancy sauce where you can save your file and refresh the page [3]. Also I admit I'm not really a big fan of DrRacket: I've just been using it for the tutorials because I have no idea what to expect from Racket, but I'm slowly moving to Emacs, and Racket seems to work fine there.
Definitely worth checking out Pollen if only to get a light introduction to the thoroughness of Racket documentation (they definitely do things differently in Racket-land!), but stay for the tools you need to roll your own ultimate static blog generator.
(Also, completely unrelated: cool video and cool title at another RacketCon 2013 talk: "Racket on the Playstation 3? It's Not What you Think!" [4].)
[1] http://pkg-build.racket-lang.org/doc/pollen/
[2] https://www.youtube.com/watch?v=20GGVNBykaw
[3] I've made a request for no-refresh updates: https://github.com/mbutterick/pollen/issues/35
Hence, Lisp code is made of nested lists. When you think further about it, it means that Lisp metaprogramming facilities may do things just with plain list manipulation functions! So it's not about metaprogramming itself, it's that it's incredibly easy. This is what people refer as "code as data" and "homoiconicity" and so on.
Yes, all programming languages are programmable. But Lisp tends to be unlimited in its programmability, in almost the same way that Unix is: if you have root, you can change anything. I'm pretty sure that in most Common Lisp systems, you can redefine large parts of the compiler at runtime. And so on.
Syntactic macros are just one part. They can be extremely handy. Lots of Lisp systems use them well. Random examples: the DEFSYSTEM macro of ASDF; the DEFINE-EASY-HANDLER macro of Hunchentoot (a Common Lisp web server); the (controversial) LOOP and ITERATE macros; etc.
Another somewhat random example: Movitz was (is?) a project to write an x86 kernel in Common Lisp. It actually included its own compiler. It defines a lot of macros for instruction definition [0] and uses them in code that I don't understand anything of [1] but is probably very clear to someone versed in assembly.
Recently I've been trying to add some nice logging to a JavaScript program, and it's a typical scenario where the normal syntax is just annoying enough to make the code ugly and hard to scan—if I had macros, I could invent some other syntax.
How to use macros is a tradeoff that I guess comes with Lisp experience, but they can be a powerful escape when the standard syntax is annoying, and a way to define your own DSLs without restriction.
[0]: https://common-lisp.net/viewvc/movitz/ia-x86/def-instr.lisp?...
[1]: https://common-lisp.net/viewvc/movitz/ia-x86/instr-add.lisp?...
How would you write a program to write a program? How can you use this generated program in your other code? It's really hard to do with a lot of programming languages, even those that have eval like JavaScript, so it never occurs to people that something like a template system or a code translator/DSL should be trivially easy to write.
Lisp uses prefix notation. With mexpr[1] it uses infix notation.
And so on.
A given language makes certain ideas easier or harder to formulate, and thus easier or harder to have in the first place. So the language constrains not only how you think about your program, but what you think—and thus what the program itself becomes.
Platforms, communities, and culture also help determine these things, but they're not independent of the underlying language.
Java on the other hand, now that's a horrible language ;) ;)
I appreciate the author's wanting a more explicit and practical answer to this question, but I don't think his answer here ("expressiveness") does any better job than the other explanations he criticizes.
> But [learning Lisp] also requires an investment of about 100–200 hours. That's asking too much.
No, it's not. That's how long it takes sometimes, or longer. Why do we all expect answers and understanding to come so quickly and easily? It'd be a nice world otherwise, but almost always enlightenment comes at a cost: patient focus and study.
And also, last time I looked at Racket, it seemed very focused on academics. I just wanted to write some simple Scheme in a .scm file and try it out (a script), but I think I had to choose a language first (maybe a line at the top of the file? Don't recall) --- the Racket ecosystem seemed off-putting.
Point taken, but troll-mode pedantry: (x + (1 if is_true() else 2)) would be valid :)
For more on the per-
ils of taxing reader
patience, see
WHY DOES TY-
POGRAPHY MAT-
TER
This quote, hyphenated as is, provides all sorts of opportunities for snark. Instead I'll just note that it seems Pollen needs work. It's far too eager to hyphenate; doesn't protrude hyphens, commas, etc.; and doesn't use TeX-style paragraph-level optimization. Not being able to identify the bounds of hyperlinks is also a strong source of irritation.