HACKER Q&A
📣 behnamoh

"Lisp can be written in Lisp.” Why is it a big deal?


Paul Graham explains in his Roots of Lisp article that one can write a Lisp eval in Lisp itself. Interesting idea, but then, so what? I've seen many Lispers claim that this is one of the powerful features of Lisp, but I don't understand what they mean. If I already have a Lisp (written in, say, C), then why would I need to write Lisp in itself? Isn't it circular? I have a feeling that this is kinda meta and there's a deeper "enlightenment" in it, but what is it?


  👤 lispm Accepted Answer ✓
Remember when you learned how recursion works?

This is a similar case. You'll learn how to understand how a Lisp interpreter works. You'll get an extremely simple one, which is written in itself. The same primitive language which is interpreted is used to write the interpreter. That's basically the local maximum of simplicity. You'll reuse much of Lisp, including the data structures, I/O, memory management, etc. But you can concentrate on the core of the interpreter: how does it process lists of code to compute a result. Thus you'll see a minimal language applied to itself. The minimal language can be written in very primitive list processing operations in a few lines of code.

I've taken one of McCarthy's example interpreters and made the language Common Lisp compatible. One can then load the interpreter into Common Lisp and run example programs. Which example programs could we run? We can run the interpreter itself. Then we have an interpreter of the small Lisp, which runs itself and which itself is running in a larger, but compatible, Lisp.

https://gist.github.com/lispm/d752d5761f7078de4041d4e453e70c...

When you run this Lisp in Lisp, you can debug itself, while it is running in itself... which you can then debug, too.

Once you understand how this simple interpreter works, you can then start thinking of changing it: tweaking the implemented language, making it faster, implement a larger language, ...


👤 eesmith
For that matter, a Python implementation can be written in Python (PyPy).

The main point by Lisp-ers is that the language is just code, and a Lisp program can be modified using the same techniques as you would any other code, and it's easy to do - much easier than almost any other language of the time.

Definitely easier than implementing Python-in-Python is now.

Why would you need it? I believe part of it comes from the idea that you should create a domain-specific way to express your problem, letting the solution naturally fall out. That might not be Lisp, but something that can be converted to Lisp (eg, through a macro) or interpreted by Lisp. If you know how to make a Lisp, you know how to make an interpreter for many other small languages.

Not that my opinion carries much weight, but, I dislike the "Lisp can be written in Lisp" argument because I think it's cheating to re-use the garbage collection of the underlying Lisp implementation.


👤 jonjacky
It's an historically important idea, which Lisp originated. Lisp in Lisp is not just an implementation - it can be the language definition - that was the big innovation. McCarthy's original Lisp was defined in Lisp, in academic papers and its manual. And, it didn't take a lot of code -- maybe a page. This shows that the language is very expressive and also compact.

The near-contemporary languages FORTRAN and Algol were not defined in themselves. Exhibiting (for example) an implementation of FORTRAN in FORTRAN would not be enlightening - it would be this big complicated thing that would be much harder to understand than Lisp in Lisp.


👤 Leftium
One practical advantage is language features can be freely added/used without requiring/waiting for users to update their platforms to a new version.

- F# implemented futures (promises) in F#. So any F# platform could immediately start using futures without having to upgrade the language runtime. I think C# and JS were able to polyfill promises, but the simpler async/await syntax could not be polyfilled. (It might be possible with transpilers like Babel.)

- In a similar fashion, some JS features were implemented as polyfills to support browsers that lacked support.

As others comments have mentioned, the big take-away from "Lisp can be written in Lisp" is the concept that data and code are the same. Code modifies data. Code is just data, so code can be used to generate new code.

One of the practical applications is you can write a domain-specific language (DSL). Not only can you write "Lisp in Lisp," you can also write specialized languages made to perfectly handle your use case.

I believe Paul Graham made a DSL for e-commerce sites which helped him stay ahead of the competition:

1. His DSL was at least one level of abstraction higher than what everyone else was dealing with.

2. Lisp's recursive/tree structure was a good match with the structure of HTML documents.

Of course, functional programming is just a way of thinking; it can be implemented in non-functional languages; FP languages just make it easier.

I forgot where I learned all this, but this article seems to explain in more detail: https://hw.leftium.com/#/item/606619


👤 taeric
I gave a stab at what I found neat about the "code as data" take before. Basic assertion is largely that the same language you use to talk about a program can be the same language that makes a program. The example I used was the code that would take the derivative of a function. You could do this in basically any language, of course. But the fact that the data structures and general code constructs is the same for the code that make a derivative is fairly unique in lisps. (Link: https://taeric.github.io/CodeAsData.html)

It also basically requires that there is very little that the language can do, that you could not also do. Which is in stark contrast to a lot of languages.