4 ms·
I recently posted my observations about taking an interest in Common Lisp and a few people kindly pointed me to this resource, which was very, very helpful. If
by troad 2y ago
I recently posted my observations about taking an interest in Common Lisp and a few people kindly pointed me to this resource, which was very, very helpful.
If you, like me, are drawn to Lisp because of its reputed elegance, just bear in mind that Common Lisp is probably the least elegant of the Lisps, though probably the most mature. It uses dated mnemonics that won't be intuitive to someone coming from modern languages, and in many ways it's surprisingly hacky. I've been pointed at Scheme, Clojure, and Racket for examples of more elegant Lisps, with Clojure probably being the most day-to-day useful of the three (albeit sadly it runs on the JVM - talk about the Beauty and the Beast).
The two big (but very basic) observations that made Lisp click for me: (A) Those nested parentheses directly indicate the AST of a Lisp program - Lisp syntax doesn't just feature lists, Lisp syntax is those lists (Lisp = LISt Processing). A Lisp program is just a single list made up of other lists. There's almost no other syntax you have to learn. Operators are just functions, which are just lists. (B) Working with a REPL allows you to climb inside of a program in a way that working with an 'Algolian' language doesn't. All the functions are there for you to play with. Using a REPL seems to be iterative; programmers will work in text files (in e.g. emacs) and then jump into a REPL every now and again to test and prod and poke at the code.
Cumulatively, those two insights I think define what is special about Lisps. Since everything is a list, you program by defining more complex lists around simpler lists, which - like Legos - you can freely manipulate with a REPL. This allows you to build programs from the inside out, compared to Algolian languages. You can build all the bits and pieces well before there's any main() method to unite them. It's not theoretically impossible to work with C or Rust like this, but the tooling around Lisp makes this easy and fundamental.
On the flip side of this, how one is meant to distribute finished Lisp programs is very unclear to me. It appears that to ship a Lisp program you basically ship the entire development environment, plus all your source code, and point the former at the entry point to the latter. I'm almost certainly missing something obvious here though, and I'm happy to be enlightened on this point. I honestly don't know how one would distribute a closed-source binary where they don't necessarily want the end user to be able to use a REPL on the code. There appears to be a proprietary compiler called LispWorks that can do this, but with prices in the four figures that's far too dear for a merely intellectual curiosity about Lisp. (There's a hobbyist edition of LispWorks, but my policy is not to spend time learning tools I couldn't turn to professional use.)
- nlitened 2y ago> Clojure probably being the most day-to-day useful of the three (albeit sadly it runs on the JVM - talk about the Beauty and the Beast) If you persist with it, later you find out that Clojure kisses the JVM, and it turns out that the JVM has been a beautiful prince all along under the Java curse.
- lispm 2y ago> Lisp syntax doesn't just feature lists, Lisp syntax is those lists (Lisp = LISt Processing) Lisp syntax is on top of lists. Lisp has as basic forms functions, built-in operators and macros. Each new macro implements syntax. > On the flip side of this, how one is meant to distribute finished Lisp programs is very unclear to me. In SBCL you would compile all the code to machine code. A program is then a single file with the Lisp runtime (providing threads, memory, garbage collection, OS, ...) and a snapshot of the Lisp heap (all the Lisp objects in memory), which is called a Lisp image. That's an executable. If you start the executable, it starts the Lisp runtime, restores the heap from the file and then hands over control to a defined entry point in the heap. ECL (another Common Lisp implementation), compiles all CL code to C and then uses a C compiler to create loadable compiled C code. The runtime then loads the compiled code on startup. LispWorks does something similar like SBCL, but LispWorks can remove unneeded functionality from the heap plus can optimize the needed space. Thus the applications can be more static and also can be smaller. Imagine one would write a, say, CAD application in LispWorks. It could start into a GUI application and the user may never see any Lisp REPL. But a REPL could be a tool for the user, where she/he can script the CAD system.