LISP as a Learning Language


LISP is easier to learn than other programming languages.

Learn LISP First

It’s slower to learn JavaScript alone than LISP with JavaScript.

For a long time, MIT’s intro-to-programming course (SICP) used Scheme (a LISP dialect). SICP is still considered to be one of the best classes on programming — I highly recommend watching the entire series on YouTube.
In most programming courses, most of the work is struggling with syntax. For-loops, arrays, function-declarations, and variables have their own unique notations that need to be covered.
Compare that with LISP, whose syntax only takes a few hours to grasp.

So why not learn about lists and functions and stuff in a dirt-simple language?

Learning Programming is Hard

Why doesn’t it work?

Syntax is not something that advanced programmers think about regularly. Real programming problems are usually about abstraction and systems and performance.
Once you’ve learned the basics of Ruby, it’s easy to jump to Python or JavaScript. Notation is not a huge deal when you’re comfortable with the underlying concepts.

Professional programmers spend their time on logical and systemic errors. Beginners spend their time on logical and conceptual and syntactical errors.
LISP minimizes conceptual and syntactical errors, because there’s only a few concepts and syntax-rules to learn. This lets students focus on what matters.

It’s hard to get unstuck when you’re learning to program. You don’t know what you don’t know, and you don’t even know where to start. With LISP, it’s as simple as “Keep simplifying the program until you can’t simplify it anymore”:

; Start
(/ (+ 8 1) 
    (list "a" "b" "c")))

; Step 1
(/ 9
    (list "a" "b" "c")))

; Step 2
(/ 9

; Step 3

And with LISP, it’s easy to experiment! Every part of the program is a valid program that you can run in an interpreter. You can copy-and-paste almost anything to see what it does.

Syntax is Hard

What do for-loops return?

When you’re a beginner, every character is a trap.

Think about how difficult it would be to make a compiler for C, Javascript, or Python.

We forget that when you’re programming, you are the compiler. So why not choose a language with simple compilation rules?


int main()
  const char *names[3];
  names[0] = "Sally";
  names[1] = "Joe";
  names[2] = "Tommy";

  for(int i=0; i<3; ++i) {
    printf("%s\n", names[i]);

Consider all the notational concepts to cover in that C snippet.

main() {...}, for(...) {...}, and printf(...) all have vaguely the same shape, but they all do completely different things. main() {...} is a function declaration, for(...) {...} is an iteration structure, and printf(...) is a function call. How do we expect beginners to learn this‽

Here are all the syntactical structures in the C program above:

#...<...>(header declaration)
... main() {...}function declaration
int ...types
int main() {...}the main function
const ...;constant variables
... = ...assignment
*...[...]array declaration
for(...) {...}for-loops
... < ...inequalities
printf(...)printf (and %s)
...(...)function calling
...[...]array access

Holy h*ck that’s a lot of stuff to learn!


var names = ["Sally", "Joe", "Tommy"];
for(var i in names)

Javascript is definitely easier than C, but you’ll notice that there’s still a bunch of ground to cover in terms of notation:

var ...variable declaration
... = ...assignment
for(... in ...) ...for-loops
...(...)function application
...[...]array access

There’s two places where beginners will likely get tripped-up with notation here in this JavaScript snippet. Why is console.log(...) is a function, but for(...) isn’t? They both have parenthesis afterward, but why do they behave so differently? And why does [...] create an array but names[i] uncreate an array? And what happens if you do names(i) or console.log[...]?

Alternatively, you could use a functional approach:

["Sally", "Joe", "Tommy"].forEach( console.log );

Note how much easier this code is for beginners:

...(...)function application


for name in ["Sally", "Joe", "Tommy"]:

The Python code seems easy, but there are still so many concepts to cover in a simple snippet. It’s not obvious what name is doing, nor what the relationships are between for, name, in, and print. They all look like normal words, but each of their functions are very different.

for ... in ...:for-loops
...(...)function application


(for-each display
 (list "Sally" "Joe" "Tommy"))

LISP is easy.

Note the lack of variables and assignment — there’s no moving-parts to hold in your head! Just functions.

(... ...)function application
(list ...)lists

Note the lack of weird for-loop syntax — all you have is a plain for-each function! And function application is easy to teach: the first hting in the parentheses is always the recipe, and everything else is an ingredient, i.e. (recipe ingredient1 ingredient2).

There are no weird exceptions or special control structures. You can always follow a simple set of rules to reduce your program into a state you can understand.

And if you don’t recognize a function, you can easily look it up online. It’s not easy to look up Python’s for-loops online, because there are so many things that can go wrong: comprehensions, indentation, 2.7 vs. 3.0 syntax, keys, range(...), iterators, dictionaries, variable-name conflicts, etc. Seriously, take a look at how many nuances there are to for-loops in Python and it’ll make your head spin.

Processes are Hard

Objects are Hard

Syntactic Sugar is Hard

Variety is Hard

Data Types are Hard

Data Structures are Hard

Mutability is Hard

list    Return a list containing the arguments.
first   Return first letter of a word, or first word of a sentence.
rest    Return all but the first element of a list. 
cons    Prepend an element to a list.
define  (Special form) Create a global name (for a procedure or other value).
equal?  Are the two arguments the same thing?
if  (Special form) Choose between two alternatives (see here).
lambda  (Special form) Create a new procedure (see Chapter \lambchop).