Jolie Rouge


all ur parentheses Я belong to me


Dr. Strangelisp, or How I learned to stop worrying and love the parentheses

The issue with Common Lisp for imperative language programmers is that Lisp has no structure around which to orient oneself. Here I mean structure in the sense of an imperative programming language. There are a lot of symbols in imperative languages that are used to orient you, like guide rails. To an imperative programmer, Lisp leaves them awash in a sea of parentheses, they don’t see the structure that is in fact there.

(defun hello-world () 
    (print "Hello World"))
(hello-world)

Does not seem so scary to me, in fact, it looks rather like:

function hello_world()
    print("Hello World")
end
hello_world()

Our issue, at first is that there is no presence of end as a signal that definition is complete. In fact, the signal that definition is complete in Lisp is “)” which is identical to the signal that definition is beginning, or that formal arguments are being defined, or that a new “block” is being created, and ended. All of these are signaled with the same lexical symbol, which is to say that are almost not being signaled at all!

With such a trivial definition it’s easy to say that Lisp is easy, but as programs grow, our issue, the lack of signals, only grows with it.

Another issue is that I have programmed my own code highlighter. My code highlighter uses a consistent color for all “keywords.” But Lisp doesn’t really have keywords in a technical sense, because all keywords are really just more kinds of functions. This can easily become confusing. But of course, for all practical purposes, defun is a keyword. In fact, it’s possible for us to say really that any normally inbuilt function in Lisp is a keyword. Why not? Who is going to stop us?

(dotimes (i 10)
    (print i))

I think we can figure out what this does. But dotimes is a Macro! Not a keyword! Who cares? It really is, for our purposes the same difference. In fact, for almost all cases of trivial programs, the existence of macros is irrelevant.

(loop for i from 1 to 10 do (print i))

Which is a particularly lucid way to loop.

(defun ++ (x)
    (+ x 1))
(++ 1) 

I wonder what the above means? But then that indicates that even operators are functions in lisp, and we can define new ones on the fly! That is both good (after all, c++ has operator overloading) but that also means that we cannot orient ourselves by some fixed point in Lisp because anything (keywords, operators) could be (and sometimes are) redefiend! How will we know what anything means!

(defun greeter (person)
  (lambda () (print (format nil "Hello ~a" person))))
(funcall (greeter "Jolie Rouge"))

That looks a bit confusing! But is it really so different from:

function greeter(person)
    return function ()
        print( string.format( "Hello %s", person ) )
    end
end
local g = greeter("Jolie Rouge")
g()

How about this for weird?

(defvar *people* '(("Jolie" "Rouge") ("Angelina" "Jolie")))

That’s a bit obscure, notice the use of ‘, which is an alias of quote. Also, the variable name “people” has * on either side of it, that has to mean something right? Well, it doesn’t. The quote mark is a signal, and it means “That which follows is data, and not code.” The stars are just another kind of character that can appear in an identifier. That’s another issue that can lead to confusion with imperative programmers, because * is not an operator, it’s just a function, and it’s name is just another name.

Consider this equivalent statement in lua:

people = { {"Jolie", "Rouge"}, {"Angelina", "Jolie"} }

Notice how I did not use local? I didn’t because in Lisp, a variable starting and ending with * is conventionally meant to imply that it is a global variable.

I wonder how we might add to this list?

(push '("Jolie" "Blond") *people*)

Which has its parallel in Lua as:

table.insert(people,{"Jolie", "Blond"})

Already we are getting into the topic of structured data. A common idiom in imperative languages is the struct, which I will illustrate in C because Lua has no structs, per se only hashmaps.

struct Point {
  double x;
  double y;
};

int main(void) {
   struct Point p = { .x = 1.1, .y = 2.3 };
}

Which is a common enough idiom in C that it should be fairly obvious what is being done. In Lisp there is a little magic happening that can be a little confusing at first:

(defstruct Point x y)
(defvar p (make-point 😡 1.1 :y 2.3))

In this case, the function make-point is created for us when we define a struct.