Friday, June 8, 2012

Land of Lisp Chp3 Summary

In the chapter 2 summary I started digging into the language based on vague remembrances from trying to learn Lisp a few years ago. It didn't work out back then, for various personal and (probably) psychological reasons but we're moving forward this time. Anyway. I might as well have waited (I'm glad I didn't though) because chapter 3 fulfills.

I must begin with the parts I find boring because an understanding of them makes the remainder of the summary more clear and easier to write about. So syntax in Lisp is composed entirely of parentheses. You have a (, a series of symbols, and a ). The () bounds lists and lists compose the semantics of Lisp.

So what kind of data types are recognized by the interpreter? Symbols are composed of alphanumerics and certain symbolic characters ( +,-,=,_,/,*, &etc). I don't know the exhaustive list of allowed characters, that's what google is for. Symbols are case insensitive (though apparently common practice is to avoid capitals).

There are two kinds of numbers, integers and floating points. Lisp handles these pretty much silently, like new interpreted languages, converting ints into floats anytime they're calculated together. However unlike newer languages (that I'm aware of) uneven division of integers does not generate a floating point. (/ 4 6) yields [2/3] not 0.66666666... . Of course [( / 4.0 6)] gets 0.6666667 as one would expect (presumably to the precision defined in code or the default precision of the interpreter). The book also assures me that 2/3 is handled appropriately by the interpreter going forward.

A corollary to the above is that it suggests that one could input rational fractions directly into the interpreter and expect them to be handled properly rather than needing to convert them to irrational numbers first (or have the code do, which will invariably end up creating a float eventually when what you really want is an int, but I digress).

Moving right along, finally we have strings. Quite conventional, they're anything in double quotes and honor the usual escapism with \'s.

An important point is knowing how to tell Lisp when you're entering data instead of code. By default the interpreter treats input as code. Using a single quote you can instead have it treated as data.

This is called quoting, appropriately enough, and causes the interpreter not to evaluate the quoted block. This is largely glossed over here, possibly to be expounded upon later.

Earlier I stated that everything in Lisp is a list. This is only part of the truth. First a little vocabulary correction. I started calling commands like ash and let, and function names keywords. It seems that these are more properly called symbols as discussed above. Groovy. It's just a word, but it should be self-evident that in languages words are of the utmost import. To move on with the point the list is only the second most important structure in Lisp. In fact I think one could say that there are structures in Lisp that are not lists. These are the things that lists are made out of. While it is clearly possible to have a list of lists one must assume that at some point a list must contain something other than another list. Otherwise you might as well say that you have an unending progression of nested boxes each containing yet more boxes. Fascinating mental simulation and yet quite pointless. At some point you reach data which is composed of multiple points which are not themselves a list. This sentence for example is a list of words, and formatting characters. Each word is a list of letters. Each letter is indivisible (semantically, the pixels constructing the letter onscreen have no semantic meaning). Thus the letters in a sentence are the data points.

Ugh. Let me dig myself out of that rabbit hole. I go rather far afield sometimes trying to find and shape a good metaphor. Moving right along. Similarly, each list in Lisp must be composed of something besides lists eventually. That something is the cons. Earlier in chapter 2 I called the second list in a let statement a list of tuples. While this may be strictly accurate my understanding now is that they are handled internally as conses. A cons consists of pointers to precisely two items. I immediately leap ahead and start thinking 'linked list!' which is good, but I have to restrain myself. I'm getting to that. Before I get any further let me elaborate on the command structure. Every command in Lisp follows a specific structure in it's list. A command list is called a form and consists of a special command symbol (generally a builtin or function) followed by a list which will be presented to the special command as parameters. This works the same for builtins and user defined functions.

So the second item in the let syntax is a list of conses to be presented to let as a parameter (yes, singular, it's only one list). Now here's the interesting thing. The the items in a cons can be a pointer to another cons. Here is where linked lists come in. Every list in Lisp is a collection of linked conses.

Now. To create a cons one simply uses the cons command. Brilliant innit?

Don't ask me how to use that syntax to reference an existing cons in an existing list. I haven't got that far yet. So now we have 3 ways to create a list. We can cons it together from constituent parts

We can explicitly declare a list

Or we can imply a list in data mode and let the interpreter sort it out

Is one way better than the other? Hell if I know, but it seems to me that explicitly using list would be less prone to human error than the consing method and less susceptible to interpreter shennanigans than implying one in data mode. But then again I'm a neophyte. What do I know?

There are two primary means of manipulating a list by its conses. Those are car and cdr. car gets the first element. For a variable, the name; for a function, the symbol of the special command. cdr gets the second element.For a variable, the value; for a list the second element of a cons is the pointer to the next cons in the chain so what you get is the original list minus the first element (instant stack behavior). These two can be combined to access arbitrary elements of lists; to parse it you have to read the symbol right to left. For example cadr gets you the first element of the second element of the original list. For example the cadr of ("coffee cup", "mouse", "laptop", "phone") is "mouse". The cddr of it is ("laptop", "phone").

These combinations are implemented as builtins up to 4 layers deep however I suspect how deep they go is at least partly implementation-specific even if that isn't stated explicitly. Nevertheless it's easy enough to define them yourself. cadr is equivalent to saying


Chapter 4 is... you know what? I can't be bothered to manually do a linked list out of these. Just hit the land of lisp tag and be done with it.

No comments: