Common Lisp — Enter the Matrix
You usually start out learning lisp like other languages: you’re just trying to learn the syntax of various commands and the quirks of how everything fits together of the concepts that you probably already know.
Then one day, you wake up, and you look at code, and some switch you weren’t even aware of has flicked in your brain, and it all looks different.
The mental effect this has on you is not unlike that scene towards the end of the matrix where Neo looks down the hallway and his perception of the thing he’s been interacting with this entire time just fundamentally changes. Its no longer writing code, that is to say, strings of text. Its interacting with and perceiving the very structure of the programs themselves.
The funny thing is, they always say they’re Neo in the matrix, which I understand is cooler, partly because that final scene captures the phenomenon of what it feels like, but its arguably summed up in a more lackadaisical way by the character Cypher in one of his quotes from the same movie: “You get used to it, though. Your brain does the translating. I don’t even see the code. All I see is blonde, brunette, redhead. Hey uh, you want a drink?” (credits ACow_Adonis on Hacker News)
The below is a modified extract of my freely available Common Lisp By Example Guide, available on GitHub (click here).
Lisp, the first language of AI:
Lisp was invented in 1958 by John McCarthy, the father of AI at the Massachusetts Institute of Technology, and evolved in the Stanford & MIT AI Labs (among others) over the next 20 years. It is the second oldest programming language in active use after FORTRAN and the world’s first functional programming language. Functional programming is all the rage today, but none of today’s languages come close to the raw power of the Lisp.
At a most basic level, a programming language is a set of rules (syntax) to convert text into machine code. Source code is stored as strings in most text-based programming languages and must be parsed by the compiler according to the syntax rules of the language. This is not the case for Lisp, which expresses source codes in a primitive data structure known as lists that can be directly evaluated by a Lisp compiler or interpreter.
This has a profound impact on the use of Lisp and the benefits it confers to its users. Lisp code is a first-class data object in the language, and can be manipulated in much the same way as any other data structure such as being dynamically created, destroyed, passed to a function, returned as a value, and have all the rights that other variables in the programming language have. This allows us to write programs that can generate and manipulate source code in much the same way as any other data object.
In this sense we say that Lisp programs can write their own program, a truly remarkable result that resembles the next frontier of automation.
In the following, we will give a brief glimpse into the basics of Lisp. Hopefully it wets your feet and jumpstarts your journey, putting you on the road to becoming proficient and effective in what I and many others believe is one of the most beautiful and elegant languages today.
Lisp is an interactive language and all Lisp systems will include an interactive front-end known as the toplevel. We can enter Lisp expressions into the toplevel and Lisp will evaluate them and print their value. This is known as the Read-Eval-Print-Loop, or REPL for short. Lisp expressions that are meant to be evaluated are known as forms.
Atoms are the most basic unit of Lisp, representing singular objects, such as the number 5 and the string “Hello, World!”. Lists are collections of atoms or other lists, separated by whitespace and enclosed in parenthesis, such as
(1 2 3) or
(“Michael” “David” “Ben”). An example of a nested list would be
((1 2 3) 4 5 6). Finally, Lisp utilises prefix notation throughout the language, meaning operators precede their arguments. For example, we would calculate 2 + 3 as
(+ 2 3).
Evaluation of Forms
Lisp applies a consistent set of evaluation rules for atomic and list forms. Atoms evaluate to themselves. For example, the number
8 appearing as an atom within Lisp code will evaluate to
8 and the string
“Color is gold” will evaluate to itself. Note that lists themselves are a collection of atoms; in evaluating a list, we need to evaluate each of the atoms individually and then apply the rules for the evaluation of the list.
Lisp will evaluate a list by looking up its first element and determining whether it represents the start of one of four types of forms: function, special, macro or lambda. The remaining elements of the list are passed as arguments to the code block named by the list’s first element:
A list whose first element is the symbol for a function name is known as a function form. Lisp will evaluate the remaining elements of a function form and pass them as arguments to the function bound to (i.e. named by) the symbol. For example, the below form evaluates the arguments to
15 respectively (each itself a result of a function), and pass them to the function call to return
(+ (+ 5 5) (* 5 1) (+ 10 5)) ; Returns 30
The evaluation rule for functions (to evaluate all the arguments and pass it to the function named by the first element) is not suitable for all scenarios. For example, in an
IF conditional, we only want the true statement to be evaluated if the condition is true and we only want the false statement to be evaluated if the condition is false.
In the below, we only want to divide
10 by the value stored in
X if it is not zero (as otherwise we will get divide-by-zero error). In an
IF conditional, and in many other language constructs, we do not want each element of the list to be evaluated.
(defparameter x 0)
(if (zerop X) ; Test if x = 0
“Cannot divide as X is zero” ; Do this if x = 0
(/ 10 X)) ; Do this if x not 0
Indeed, Lisp has specific evaluation rules for functions, special forms, lambda forms and macros. However the basic principle is the same — Lisp will look up the first element of each list and then apply the relevant evaluation rule, utilising the remaining elements as arguments to the language construct called.
Now try entering the following list into our toplevel. You will receive an error. This is because Lisp will look at the first element
1 and is unable to evaluate it as
1 is a number, not the name of a function, special form or macro.
(1 2 3) ; Error as 1 is not a function or a name for another code block (special form, lambda form, macro form)
The above is just a glimpse into Lisp, taken from my concise 52 page guide “Common Lisp by Example”. You can get a copy of my guide freely on GitHub with the following link. If you like it, please do star it on GitHub:
Repo for Common Lisp by Example GitHub is home to over 50 million developers working together to host and review code…
If I can ask of you one thing today, it is to dedicate just 10 hours to learning Lisp; a small bit of work now that will hopefully open you up to a world of new possibilities in programming in the future. Lisp is a beautiful symmetrical language that is very powerful and elegant. Many of the concepts used in other languages today originated from Lisp. It is not much to spend just a little bit of time learning Lisp and hopefully it will be of significant benefit to you.
As with everything in life, we need to put in work to get results and I won’t underplay the effort required to get acquainted with Lisp. However, I truly think it is very much worth it.
The easiest way to install and start writing code in Common Lisp is via the free Portacle app. No excuses now!