Saturday, November 3, 2012

Sad and Disgusting

I meant to come back and articulate some commentary about this, but it's been sitting in draft form for a while now. Might as well post it since the only commentary I've bothered to put to sentence is a pretty good summary.

This is sad and disgusting
http://www.nytimes.com/2012/10/15/us/seeing-a-homosexual-agenda-christian-group-protests-an-anti-bullying-program.html

LISP on hold, NME on go

I have abandoned or put on hold (more or less indefinitely) far too many projects in my life. Hopefully this one will be short. Having discussed things with the family I'm putting LISP on hold and starting to learn Haxe NME first.

On a largely unrelated note, I need a new keyboard. This one is crap and I make more typos than monkeys trying for Shakespeare. Too much time on a laptop keyboard have made the keys on a full size keyboard feel too far apart.

Saturday, October 13, 2012

Land of Lisp chapter 8

In chapter 8 we build a Wumpus-style game. And if you recognize that reference then you must be at least as old as I am and allow me to reassure you that this will not be the basic Wumpus of yesteryear.

No, we're making Grand Theft Wumpus! Grand Theft Wumpus includes a few twists on the traditional Hunt the Wumpus game. The story is different but I'm not going to get into it. Buy the book for that. Suffice to say that you have one bullet, you're looking for the Wumpus, there are Glowworm Gangs that will mug you and ditch you elsewhere, and there are police checkpoints around town that end the game for you. Exciting!

The GlowWorm Gangs (GWG) are at random nodes in our game graph (yes, we're going to leverage that again) and the police blockade random edges. You can see GWG lights from one node away, you can hear sirens on the nodes to either side of a checkpoint, and the Wumpus has left a trail of blood that is visible in any node (bizarrely enough) up to 2 nodes away from himself. As the player you can move around town dodging checkpoints and exploring the randomized terrain and when you think you have the Wumpus pinpointed you charge in with your last bullet and win or lose based on your deductive reasoning.

That's the basic mechanics. Of course, the code involves rather more complexity than that so let's get started. First we have some basic parameters and helper functions.

The game's operating parameters appear first (the book helpfully forgets to include the *player-pos* parameter which made a nice troubleshooting exercise). random-node just returns a random number between 1 and the node max (*node-num*) inclusive. edge-pair returns a list of edges that describe a two way path. We'll use this because the game world is going to be an undirected graph meaning we need the edges defined in both directions. Finally we have make-edge-list which gets us to our first interesting (sort of) bit. Here we use a loop to collect a bunch of edge pairs between random nodes and then append them all into a single list.

Let's take a look at the structure of loop since it appears to be a bit awkward. The spec (google CLISP hyperspec) is dense with meaning and utility but in this chapter we only use it with two 'name clause's. We use a loop for and a loop repeat. loop for is your basic for loop with a defined index variable and a range for that variable over which the code block executes.

loop repeat just repeats the code block for the specified number of times.


You may have noticed the collect symbol in there. Based on my understanding of the spec (minimal I assure you) that's called the main-clause of the loop and in this case is an accumulation-clause, sub category list-accumulation, called collect. How that differs from append, collecting, or etc as referenced in the spec I wish I knew. Suffice that it will give us a list of edge pair lists, as in (((1 . 2) (2 . 1)) ((2 . 3) (3.2))), which is sort of what we want. Except that's nested deeper than is practical so we use apply to append all these sub lists into a single list like ((1 . 2) (2 . 1) (2 . 3) (3.2)) which is more readable to boot.

Now you might note that make-edge-list repeats the loop for *edge-num* iterations and creates a random path each time. The astute observer will note that this will likely leave many nodes inaccesible from some or all other nodes; in short it makes islands. It also creates some duplicate edges. We'll handle the duplicates in a later function. Right now we need to get the islands bridged.

First I'm going to blast a lot of code out in order to make what might be a philosophical point.
Our island prevention code:


That's a lot of pretty dense code. I'm discovering that when I read Lisp I have to read it from the inside out. But when coming up with the algorithm it has to be written from the outside in. Which, actually, puts me in mind of a time reversible process. Once the code is written if you want to understand it you have to perform the process in reverse. Maybe I'm just clueless. Moving along. Let's look at that again with some things brought out. Unfortunately I have yet to find a way to force custom highlights into a gist, so we're stuck with basic styles for this block.

[
(defun direct-edges (node edge-list)
  (remove-if-not (lambda (x)
                    (eql (car x) node))
                 edge-list))

(defun get-connected (node edge-list)
  (let ((visited nil))
       (labels ((traverse (node)
                  (unless (member node visited)
                     (push node visited)
                     (mapc (lambda (edge)
                              (traverse (cdr edge)))
                           (direct-edges node edge-list)))))
               (traverse node))
        visited))

(defun find-islands (node edge-list)
  (let ((islands nil))
     (labels ((find-island (nodes)
                (let* ((connected (get-connected (car nodes) edge-list))
                       (unconnected (set-difference nodes connected)))
                  (push connected islands)
                  (when unconnected
                    (find-island unconnected)))))
        (find-island node))
     islands))

(defun connect-with-bridges (islands)
  (when (cdr islands)
    (append (edge-pair (caar islands) (caadr islands))
            (connect-with-bridges (cdr islands)))))

(defun connect-all-islands (nodes edge-list)
  (append (connect-with-bridges (find-islands nodes edge-list)) edge-list))
]

Now first allow me to apologize for eyestrain. I tried to pick colors that weren't too garish or hard to read against the background without spending a lot of time on it. I'm not here to make beautiful copy. If you can get past that though you'll see the patterns. Each function has its color and every function scoped inside it has a washed out color in the same shade (I'm sure my use of terms would make any artist cringe, sorry). That lets me see recursion, as well as the flow of the code at a glance. I swear someone has to have put this kind of functionality in an IDE somewhere but I'll be boogered if I can find it (no; I'm not interested in learning emacs (which from all descriptions is the panacea of programs though I don't really know if it can do this); one heavy duty learning project at a time, go away). But to the point examining the code highlighted this way it's pretty easy to see what does what.

connect-all-islands is clearly top of the heap, it calls connect-with-bridges but that function doesn't go anywhere else (except itself ;) )so we follow find-islands. It creates a find-island function that calls get-connected. get-connected defines traverse which, in addition to being recursive, calls direct-edges which is the end of the line. direct-edges is the most interior function so we'll start there and work our way back up the heap. Perhaps I'm just bad at reading code or don't have enough practice with Lisp but this is the way my brain has to work in order to grok it for some reason. Turns out the order the functions appear in the book are inside to outside but I didn't know that when I first looked at the code and, if you've worked on enough code from other people, you can't expect that to be the case in any given set of code. Anyway.

In direct-edges we find all the edges in a list that start from a particular node. The lambda function compares the car of the given edge, x, and returns truth if it's the same as the node parameter the function was called with. remove-if-not deletes any item from edge-list that returns false from the lambda.

In get-connected we build a list of visited nodes. We define a function traverse which we the call recursively against each node linked to the node parameter in the edge-list parameter. At each node we first push it onto the visited list (which acts as progress tracking, return value, and recursion limiter because the unless form controls the recursion of traverse by testing the node against existence in visited) then we map traverse across the cdr of the list of edges provided by direct-edges for the given node. In the end we return everything we've accumulated in visited.

Allow a brief interlude here to define a few new language functions. let* works precisely like let except it allows references to other variables within the variable definition form. So

will run fine (returning 8) while

will cause a parse error (specifically that variable a has no value, though it's clearly defined right there). It's important to note that order in let* matters. The variable still has to be defined before you reference it.

We'll also use set-difference which simply takes two lists and returns what is in the first list but not the second.

Without further delay the find-islands function defines a function find-island. Allow me to make another aside. I deplore the use of plurality to differentiate the interior function from the outer function, even though it makes semantic sense, because it makes it damnably confusing to read properly at a glance unless they're highlighted like above. This gets even worse when you realize that the variables node and nodes act precisely the same here. node is one of the parameters of the outer function and nodes is the parameter of the inner function. Compounding your confusion would be the fact that node is fed to find-island in the body of the outer function causing significant (for me at least, maybe I'm a dunce) mental dissonance between giving a singular variable with a single node (assuming the semantics of the variable name are to be trusted! which in fact they aren't as we'll see shortly) in it to a plural variable which (semantically) should expect to receive a list of multiple nodes. Which taken together becomes a big jumbled mess of functions and variables that all look alike. Makes it a serious task to make sense of when it's not really that complicated. Now all this is probably just a failure of my intelligence. But for me, it reads a lot better like so:


Now we have, semantically, find-islands which defines explore-island which gets all the interconnected nodes in a given 'island' and then recurses on the nodes that aren't in that 'island' (thus 'exploring' the unexplored-nodes). This is perhaps a little sparser but I can grok it easier; in particular the differentiation of the names is critical to my understanding. Now, a more detailed deconstruction.

The find-islands function defines a function explore-island which uses get-connected to find the list of nodes that can be reached from the car of the parameter unexplored-nodes and put them in the connected variable. Then (using the magic of let*) we get the set-difference of unexplored-nodes and the nodes connected to this 'island'. Those nodes are still not 'explored' so we recurse them back into explore-island after pushing this 'island' (connected) onto the islands variable declared at the top of find-islands. In the end we have a list of lists of connected nodes. A list of islands, if you will, which we return.

Now the connect-with-bridges function which just takes a list of islands (notice a relationship there?) and builds a bridge between the first two. The logic is simple, even if the code looks a bit confusing at first. First look inside the append form at one of the two parameters. We'll start with the edge-pair since it's the easier one. It gets the first node in the first island in the input parameter and makes edges with the first node in the first island in the tail of the parameter. Confused? Read the c*r's backwards. (caadr islands) takes the tail (d) of islands (the second through nth term), gets the first (a) term (or island) and pulls the first (a) term, or node, off of it. Similarly for caar. The second term in append recurses into connect-with-bridges using the tail of the input parameter. Since we've recursed we need to look at that when form now. That just causes recursion to end when the function only gets a list of one island (there aren't any more islands to connect to, obviously). At which point we start returning the appended lists back up the recursion chain until at the end we have a list of bridge edges that will join all the islands given in the parameter.

Finally, the connect-all-islands function takes a list of nodes and their edges, uses find-islands to get the list of islands, gets a list of bridge edges by feeding that to connect-with-bridges, and then appends those bridges to the input edge list outputting a list of edges that will reliably connect every node together by at least one path. Phew. That feels a lot more complicated than it really is. But if you grok all that at once then I think we're well on our way to 'learning' Lisp (said by a raw neophyte so take it for what it's worth).

We are not, however, done with the hard work of the chapter. Next we need to convert our raw edge data into an alist. We'll also add the police roadblocks, since those exist along the edges rather than in the nodes. Here's another code dump.

This is somewhat less complicated than the last batch. Starting with edges-to-alist (which is the most interior function in this batch) we take a list of edge pairs and convert it to, apropo to the function name, an associative list of nodes and destinations. The last line in the function generates a list of the nodes that act as the starting point of each edge (which is effectively all nodes since the list is an undirected graph; so I'm not sure if there's a purpose to this as opposed to simply making a list of the integers from 1-*node-num*). Duplicates are removed (which is all remove-duplicates does by the way) and the resulting list is mapped by the lambda function. Within the lambda we find another mapcar which creates a list of the unique edges in the full edge list which start from the node given to the lambda. The mapping function for this interior mapcar is another lambda which creates a list of the destinations (the cdr) of the edge given to the lambda. The list result from the interior mapcar is then consed onto the original node. The reulsting list returned by the outermost mapcar (and thus the function) looks like ((1 (2) (4)) (2 (1) (3)) (3 (4) (1)) (4 (1) (3)) for a circular map with nodes 1, 2, 3, 4 in sequence.

The add-cops function takes an alist of edges (coincidentally of the type created by edges-to-alist ;) ) and a list of edges in which there will be cops (this list is generated by the outer make-city-edges function which we'll get to next, it's an edge in the format (x . y)). The outer mapcar just feeds the alist to the lambda and returns a list of the results. The logic all occurs within the lambda mapping function. First t declares node1 and node1-edges variables by breaking up the alist element it's given by the mapcar form. The interior mapcar then takes node1-edges and maps another lambda across it. This interior lambda first declares node2 as the car of the edges it's given (recall that our alist looks like ((1 (2) (4))... so the mapcar is looking at ((2) (4)...) and thus the interior lambda gets (2) which it needs to pull out of the list in order to operate on). The destination node (node2) and the start node from the outer lambda (node1, which is still in scope) are then converted via edge-pair (which you'll recall from earlier takes two nodes and creates an edge cons in both directions between them) and the intersection function is used to see if either of edge in the pair appears in the list of edges-with-cops (using the equal function as per the :test keyword since these we're comparing conses). if the intersection function returns anything at all then the node2 (the edge destination) is consed to 'cops to flag that destination. Otherwise the original edge (as it was given to the lambda in a list) is returned. In either case the resulting list (either of the destination or destination plus flag) is consed back onto the original node and the resulting alist returned to the outer mapcar. The result of the whole function looks like ((1 (2 'cops) (4)) (2 (1 'cops) (3)... which we can then parse for cops pretty easily by getting (cdr (assoc destination (cdr (assoc start edges)))). From the inside out that's getting the the current node from the edge list, getting the destinations from that node, getting a specific destination from from the list of destinations, then looking for a cdr in the destination's list (which would be our cop flag if it exists).

And now the outermost function in this clump of functionality, where we finally bring connect-all-islands and make-edge-list into the mix. The make-city-edges function uses let* to define a variable nodes as a sequential list of all nodes in the game, pass nodes to connect-all-islands to put a list of edges in edge-list and finally uses remove-if-not to generate a list of edges with cops using a lambda function that randomly returns true at a frequency modulated by *cop-odds*. Then it runs the edge-list through edges-to-alist which is returned to add-cops which returns the final output of the whole function. Basically, all this function does is figure out where the cops go and orchestrate the dance of other functions.

So now we have all the edges ready. We also need to put together the actual nodes since they'll have some context associated with them. What context? Well there's presence of the wumpus or GWG for starters but we also will need to indicate proximity to cops, GWGs, and the wumpus using sirens, lights, and blood respectively. While we could, technically, calculate proximity to these things at each move that would be an pointless load on processing since
1) Blood spreads out by two moves which increases the search range dramatically
2) The proximity search would either have to be completed at each move or a map kept up with in memory and if we're going to do that we might as well preload it all since...
3) It only takes a few bytes of memory and doesn't dramatically slow down game initialization.

So let's build an alist of nodes which includes all the localized context of each node. For starters we'll make a couple of helper functions.


neighbors just returns a list of the nodes neighboring the given node (isn't there another function that does this up there somewhere? I'm not sure now... Damn, this post is too long). It conveniently discards the COPS data. within-one just takes two nodes and checks for the second node in the neighbors of the first.

within-two first checks within-one. If that comes up false it gets all the neighbors of the first node and uses a lambda to check if the second node is within-one of them. If any of them are then some evaluates to true.

Now for the core of our node alist construction.


First a let form assigns the wumpus to a random node and as many GWGs as the game is configured to use are given random nodes and accumulated into a list. Now the guts of the make-city-nodes function is a loop that accumulates the output of two cond forms, and a when form. This is actually relatively easy to see from the code; the first cond returns '(wumpus) if you're in the same node with him, '(blood) if you're within two nodes, or nothing. The second returns '(glow-worm) if you're in a node with the GWG and '(lights!) if you're within one node of a GWG. Finally if there's a cdr in one of the destinations in the edges alist (which you'll recall from above will be our cops flag) the when will return '(sirens). All of this is appended into a list beginning with the node number.

Our play space is complete! Huzzah! Fire up the game and let's have a go at it! What's this? Where's the health bar? These graphics suck! Who wrote this piece of ... oh right. Derp! We seem to have forgotten the UI... back to the interpreter! The new-game function is quit basic.


First things first the find-empty-node utility function does just that. There's a risk here of infinite recursion though if there are too many GWGs or cops. Basically it looks for a node with no cdr in the node map so if every node has a flag of some sort then...

new-game itself simply uses the existing functions to set up some globals. It's mostly self explanatory. *visited-nodes* is just a list of nodes we've been in to save the state of the current game. draw-city just uses our existing Graphiz functions to draw the full map of the city. What's this? draw-known-city is undefined!


Ah, there it is. Glad to see it's back on the map. So the draw function here simply leverages Graphiz again. Of more import are the two helpers. known-city-nodes uses mapcan which appends the outputs of the mapping function together into a list. It maps across *visited-nodes* and the lambda function gets the edge destinations. So we end up appending together a list of all visited nodes and the destinations adjacent to them. The duplicates are removed and then this list is fed into the other lambda which gets the listed nodes directly from *congestion-city-nodes* and appends a * to the current player position or a ? to any node that hasn't been visited yet; this allows our map of the known city to include edges to places we haven't been because the nodes need to be there for the graphing utility while also being visually unambiguous. You could accurately call the ? the "Wumpus Fog of War™".

known-city-edges works similarly. The inner mapcar pulls the edge destinations for a visited node and if the destination is in the visited list it sends the whole thing to be consed to the original node. If it hasn't been visited then it makes a list of the destination's car and just sends that. This allows COPS flags to appear on edges that you've seen both sides of.

So much for our graphics (megatextures eat your heart out, these grafixs easily scale to any resolution!). Now we need to be able to control movements within the game world.


Three simple functions. They both call the same helper function, charge just sets a flag to indicate that we're going to charge instead of just walk.

handle-direction attempts to get the pos (the node we're going to) out of the possible destinations for the player's postion in *congestion-city-edges*. If it can't then edge is false and it outputs the error. Otherwise it calls this function:


The first thing that happens is we get the player's current position into node and then we check to see if 1. there's a GWG there and 2. we haven't been there before. If both of those are true then has-worm is true (even if there's a GWG, they only mug you once; you don't look that wealthy). With those variables set we pushnew the position onto *visited-nodes*, update the current position parameter, and redraw the map of the known city. Next we check for changes in the game status. The cond checks for cops on the edge you followed which ends the game, then for the wumpus (and prints a message based on the charging flag). If the wumpus wasn't there but you were charging then you waste your last bullet. Finally, if there is a GWG in the new node it moves us to a random new position. It should be pointed out that the recursive call to handle-new-place here sends nil for the edge parameter which, by nature, fails the cop and wumpus checks above.

Now ideally when the game is over we'd set some kind of ending condition but, in this case, we'll just print some messages and go on taking input. So technically winning and losing is a bit pointless. Hey, this isn't a triple A game we're making here; it's a language demo. As for playing, it's a bit fiddly. Open the known city map PNG file created by Graphiz in your browser. Yes, that's your graphics. Now enter (walk #) or (charge #) at the REPL and reload the image in your browser. Yeh, I said it's fiddly didn't I? I also said it isn't intended to be AAA right? I'm sure I said that somewhere...

That concludes this (rather long) post. If you think it took you forever to read I'm afraid it took me even longer to write it (week long interruptions are horrible). The code files are at...
grapher.lisp
GrandTheftWumpus.lisp

You'll want to do the following:

to get things running (using the correct paths of course).

Monday, August 6, 2012

Politics + money, everyone duck and cover

Go read Lessig in The Atlantic. Want to sum up my view of politics? It's these three paragraphs. Start to finish.

As I've explained on these pages again and again, the Framers of our Constitution gave us a "Republic." By "a Republic," they meant a "representative democracy." And by "a representative democracy," they meant a government that in the legislative branch at least was to be, as Federalist 52 describes it, "dependent upon the People alone."
In the 225 years since, Congress has evolved a different dependence -- a dependence not "upon the People alone" but increasingly, a dependence upon "the funders" of campaigns as well.
But here's the obvious problem: "the Funders" are not "the People." As I've written again and again, .26 percent of America gives more than $200 to any congressional candidate; .05 percent of America gives the maximum amount to any congressional campaign; .01 percent gives more than $10,000 in an election cycle; through February, .000063 percent of America -- 196 citizens -- gave close to 80 percent of Super PAC contributions. And according to U.S. PIRG and Demos, 1,000 citizens of the United States (or so we assume) have given more than 94 percent of Super PAC contributions so far.

Mostly I agree with Lessig however I disagree with his characterization that 'dependence' doesn't equate to 'purchase.' It surely does in the same way that a you don't call a dog your dependent. You own a dog. Your children are your dependents. Corporations and the disgustingly rich  'own' Congress in the same way you 'own' a dog. That dog may have other opinions or desires but even if it can break away from you unless it can find some other food source it will never be the sleek, well fed, blue ribbon winner that it is today.

A dog that bites the hand gets beat by the hand and, surely, no longer goes to competition (never mind winning best of show).

Saturday, July 28, 2012

Ouya

I'm just giddy

Monday, July 23, 2012

Land of Lisp chapter 7

So a while back I mentioned needing a drip-feed of neurochemical triggers in the form of a productivity chart. I'm now 2 weeks late on a promise. Call it supporting evidence. So moving right along.

Chapter 7 covered more interesting list structures than have been used so far. It also comes across as quite dry so I'm liable to not spend much time in spots.


We start with dotted lists and pairs. A dotted list is simply a list that isn't terminated with nil. If we go back to thinking of Lisp lists as similar to a linked list structure a dotted list would be the same as plugging a data value into the last pointer in the chain. Which would be fugly in a linked list but works out alright for Lisp. Incidentally the dot notation used to print these lists

can also be used as a replacement for cons as in (1 . ( 2 . 3)) or for a common list as in (1 . (2 . (3 . nil))). I would assume using one form over the other would be a matter of taste and convention. The use of dotted lists regularly in code is supposedly uncommon however the book does state that running across such lists happens often which is quite contradictory and I'm not sure which side of the tale to believe. Either way I'll know what I'm looking at when I meet one. There is a relatively standard usage though in concisely describing pairs of things.

Additionally circular lists are discussed; these are simple enough to me that I'll gloss over them. Basically, the cdr of the final cons cell points back to one of the prior cells in the list. You could, if you felt like it, craft a very complex list using a combination of circular references. You'd also confuse the hell out of the interpreter unless you warned it that you were going to by issuing (setf *print-circle* t) which basically tells it to take a little longer in the print routine to make sure it doesn't get stuck printing in a loop.

Association lists (or alists) are also discussed which is, predictably, a list of pairs though presumably it's a list of keys consed to values which could themselves be further lists. Discussed here is a list of dot pairs. This is a convenient structure but apparently becomes inefficient when the list grows beyond a few items. Finally it discusses tree structures in data which we've already been using to some extent. If you've been watching you can see that Lisp lists are adept at handling trees as each branch basically has a symbol by which it can be referenced in the car of its cons cell. If I rip an example straight from the book

we can see this clearly. The *house* is composed of walls, windows, and roof. Each of which is a symbol identifying a list of its component parts.

The last half of the chapter covers Graphviz which takes formatted text input and generates image graphs based on the data. This is largely just data format manipulation code that takes the node and edge parameters defined for the wizard game and converts it to text output properly formatted for Graphviz. I'm not going to discuss this because it's largely boring; feel free to dissect the code linked below. Just as a clarification, data conversion is at the root of the beginning and ending of every program. It is vitally important, clearly, and a topic worthy of understanding. However the majority of the code I'm skipping is just string manipulation. Not only is it a thoroughly understood form of data manipulation it is, in my opinion, extremely dull; like a video game played 4 or 5 times already becomes dull in a vaguely interesting way. I'm going to cover new topics and functions introduced here but I won't be bothered with the boring details because I want my life to be more than vaguely interesting.

What I will discuss is new functionality. The substitute-if function

feeds each item in the target through the predicate-function and when true it substitutes the subvalue and returns the final result. This is demonstrated to work on lists and strings though I suspect it works on lists and a string is simply silently converted to a list of chars and back again.

The complement higher order function returns a function that basically inverts a predicate function. So

returns a function (which could be fed to another higher order function or presumably used in lambda) that returns the opposite of the alphanumericp function (which appropriately enough returns true when given an alphanumeric character). So in short, the function provided by complement above would return false when given [a-zA-Z0-9] and true for any other character.

A noteworthy concept on display in this chapter is the use of side effects. In each of the functions created to reformat the data we aren't really concerned about the output of the function itself. Instead the functions print the data to the console using princ and the output is ignored. This allows us to have greater control of what gets generated and easily review and debug that output. In the final function we'll simply capture the console output to a file. This runs against functional programming style as it relies on side effects. I honestly don't care; it works, it's clean, it facilitates code reuse (which we'll see in a minute) and I'm not religious about programming technique.

Once we've created all the functions required to reformat the data into a Gaphviz format we need to run that data through a Graphviz converter. The following function handles that task.

This gets interesting. Firstly, there's that thunk parameter. What a funny name for a symbol. According to Wikipedia (clearly the authority in computer science studies >.> ) thunks were invented by Peter Zilahy Ingerman and the term was arrived at because it's 'the past tense of think at two in the morning.' Which I can entirely believe. I'm not a hardcore compsci major but I'll do my best to take a whack at describing these, if only to help solidify my own understanding. Also called suspensions these functions offer a means of controlling the timing of evaluation of computations. Why this might be important (beyond deep efficiency mining) isn't readily apparent to me. The book makes the case that wrapping the graph->dot function inside a thunk delays the computation and allows the dot->png function to capture its output but I would argue that the same effect would be had if you simply plopped the function directly into the dot->png function as in this code

That gets you precisely the same output via the same methods. So it seems to me that what the thunk amounts to in this usage is to blackbox the creation of the data processed by the dot->png function. This is something I definitely understand and it allows us to plug any function name we want into the code above provided that the function outputs to console and (preferably) generates data parseable by the Graphviz 'dot' command. This also gets us off the hook for not actually outputting the correct data from the function directly. We use the thunk as a nullary (parameterless) function and ignore its output relying solely on the side effects of the function and the use of global values to perform the computations required.

Now, some less crunchy aspects of the function. The with-open-file function is very similar to let in that it defines a symbol to be used in the following forms.

The symbol becomes a stream variable (glossed over here) which is then available within the with-open-file form to be written to. In the usage above we very cleverly redefine the *standard-output* global stream variable (which is coincidentally the default stream for Lisp printing functions) to point to a file which is opened in write mode (:direction :output) and overwrites any existing file (:if-exists :supersede). Thus all the prints done from within the thunk (which we execute with funcall) are written to the file filename due to the dynamic value of *standard-output* from within the with-open-file form.

Now would be a good time for a quick interlude on keywords. These are symbols prepended with a colon as in :if-exists. These might be thought of as constants (though I'm unsure of the accuracy of the comparison to a C constant). They have an inherent value and that value is themselves and cannot be changed.

These are used in a number of functions to define various options such as file open modes. Options that might otherwise be incomprehensible strings of apparently arbitrary characters (yes, I'm looking at you Perl).

The last part of the chapter discusses the functions for generating an undirected graph. The siginifcant difference here is that the uedges->dot function uses maplist instead of mapcar which (as you might expect from the mnemonic) executes a function across a list (map) but instead of sending each car it sends the remaining list at each iteration (car vs list). Then the lambda function uses unless to skip any edges that are repeated later. The end result is that only the last direction of an edge gets printed but since the different directions of travel are meaningless in this context that's what we want.

The code for this chapter is at:
grapher.lisp
TheWizardAdventureGame.lisp


You'll want to do the following:

to get things running (using the correct paths of course).

Thursday, June 28, 2012

Possessions obsessions

So listening to Papa Roach, "Between Angels and Insects".

"There's no money. There's no possessions, only obsession."

I'm struck with the thought that my obsession, yes it is, with video games and more particularly the kind where you accumulate 'stuff' is a sublimation of materialism to assuage the pain of not being able to accumulate real world 'stuff' for so long. I wouldn't call myself deprived but during my childhood we never 'kept up with the Jonses' nor made even a cursory attempt to and I was given a general impression that we were broke. However I went to a school district where 'the Jonses' were effectively idolized. I felt my family's purported lack, whether 'real' or not, and now I think it has perhaps had a lasting impact on my psyche. I feel compelled (yes, that's the right word) to play certain games. Not puzzle games, not shooters. I used to enjoy enforcing mastery on a difficult system (for a long time Gradius II was the best thing in the universe when it was new) but I'm not so good at twitch mechanics anymore. All that's left is really the grind for more ingame 'stuff' which, actually, I end up finding quite boring and not fun

So recognizing this drive, can I control it? Harness it? Expunge it as poison? Games have inherent value, yes, but not the way I tend to consume them.


Coming back and cleaning up the above into something approaching coherence I had the thought that I shouldn't blame my father (that's where the majority of my impression of destitution came from I suspect) as his parents were, my my admittedly faulty estimation, poor. I imagine it takes a solid generation to expunge that from the family's psyche.
I've also read the full lyrics, instead of just listening to them, and am struck by ... well, by the whole thing. I was going to look at a couple of lines but nevermind. Here's the whole thing.

Last word. I'm amused how the close-mindedness of Religion would deprive me of such insight. Rejecting things that don't immediately fall in line with your beliefs is idiocy no matter what terms you couch it in or justifications you give. If scripture is your excuse to reject something without considering its value then you devalue scripture.

Land of Lisp chapter 6

Whoops. Naughty me, I did the 6.5 post before the chapter 6 post. Well, 6.5 was more interesting and easier to write at the same time. So it got done first. Onward; pretend all the lambda navel-gazing hasn't happened yet.

Now this adventure game is pretty ugly, and very user unfriendly. Time to clean it up a bit. That's going to require some better I/O functions.

The basic screen printing functions are:
print: Prints one output per line, strings in quotes. Perfectly machine readable later.
print1: Dispenses with the newline
princ: Human readable output.
For reading input:
read: Just the basic Lisp input, parens and quotes required.
read-line: Reads until the user hits enter and takes the whole input verbatim as a string.
read-from-string: Just like read except it takes a string input instead of reading from the console.

With that it's time to learn one of the more powerful functions. eval takes input and parses it as code. So

executes the form with the (princ "bar") output that you'd expect. This is quite powerful but also dangerous. And it's dangerous in ways that are not necessarily immediately obvious. I'll get to that.

At this point we have all the capabilities to build our very own REPL. Rather like opening a DOS shell within a DOS shell. You might compare it to running Windows in a VM except that the VM handles a lot of background operations and that would be more akin to the next step in this chapter. To the point however, here's the dead simple code for a basic, nofrills, 'custom' REPL (custom in quotes because it's about as bog standard as it gets even though it's a REPL in a REPL).

That's all well and good but when we execute (my-repl) nothing really interesting happens. Visibly at least. Because, of course, the functions we've used have no functionality beyond the basic REPL. We haven't written any. So that's clearly the next step. Now is a good time to note that I'm storing the code for this custom REPL in a separate file because it becomes essentially a general use engine for running simple text adventures. The file will be linked at the bottom along with loading instructions (such as they are).

I'd also like to note in advance that I think the way the game-repl is implemented is a bad paradigm. It basically uses recursion to perform the 'loop' structure. I added a printout to the book's code to make this obvious; basically when you 'quit' you'll get a playback of all the commands entered. Now while this implementation is tiny compared to modern memory sizes it's important to note that recursion has some overhead (which is also made obvious by the printout). It literally does not matter here due to the scales involved, I want to stress that, but it's important to note the point. Maybe this small structural complaint is fixed later in the book, I dunno. But on with it.

First we want to be able to take input. So we build game-read.

Take a moment to look at the flet function quote-it. What does (list 'quote x) do? A heretofore undescribed complexity is that we've been using a shorthand when quoting. 'foo is the same as using the quote function as in (quote foo). So what quote-it does is create a list that is a form of the quote function. It literally quotes its input and returns it. It's important to note that this case doesn't require #'quote because it isn't being passed as a parameter to a higher order function; the full special form is created using list so it will get evaluated normally. So to describe the game-read function fully, first we read a raw line of input, then we create a string (because we requested it by specifying 'string) by concatenating parenthesis around the input. Then we read that string into the cmd variable. Then we quote the cdr of the entered command (if it's more than 1 list item) using mapcar and quote-it, cons the thing back together, and return that result.

Next, we need to evaluate what we just read.


Two things to note. First, I added the case expression. It's completely missing in the book. But I'm afraid 'pickup' is just awkward to me and since get is its own special form it needed to be handled specially by the evaluation function. So I select it with case and convert it to a 'pickup' verb instead. Additional verbs can be added to the case form as needed, though if there are many then a flet might be in order . Second the *allowed-commands* global I'm placing in the game data file. It's specific to the game so doesn't need to be in the custom REPL code. It's defined as (again, I added 'get' myself to get it past the member filter):

So this is pretty straightforward. The only complexity is what I added. An if test is performed to determine if the input verb (the car of the input expression) is allowed and it's either evaled or an error is generated.

Finally there's the output. This is the most complicated. As usual.

Some of the lines probably break in the wrong places which makes it boogers to read. I really need to find a decent scroll block to plug in here, but I'm lazy and have other things to do. Look it up in the code file if it bothers you. (Edit: Should look much better now that it's in gist!)

Basically what happens here is the input list to game-print is printed to a string value by prin1-to-string which works the same as prin1 but returns the string instead of printing it to screen. That string has parenthesis and spaces hacked off the ends by the obvious string-trim function and the output from that is coerced to a list of characters. Then tweak-text is called which handles capitalization (there's nothing new in the function so I'll leave figuring out the logic as an exercise... oh wait, char-upcase and char-downcase... surely those are completely obvious...) and the resultant list of character values is then coerced to a string, princed and a fresh-line is output. Phew.

Now, to plug this all together (with my aforementioned rudimentary stack trace):

So, if you input 'quit' the recursion ends and all the input cmds are re-output.. Dead simple.

As the last word, a caveat about eval. We've pretty thoroughly scrubbed the user input right? We only accept a few verbs past the filters in front of eval, only one of those is a special form command, and that one is re-written as a different verb with no special meanings. There's still a problem though. As with anything that one doesn't fully understand there's a backdoor, apparently, in the read functionality. The book doesn't go into detail but there are apparently read macros that allow all sorts of shenanigans. Like perhaps

I don't know if there's a way to disable those or not. I'm hoping the book will cover them in more detail shortly.

The files:
gameREPL.lisp
TheWizardAdventureGame.lisp

You'll want to do the following:

to get things running (using the correct paths of course).

Saturday, June 23, 2012

Land of Lisp chapter 6.5 - Lambda

Okay, the chapter (sort of) on lambda. Perhaps I'm dense, or inexperienced, or just plain stupid but I'm not sure I see what all the hype is. This (half) chapter, for all its hyperbole, does little to dispel the mist surrounding the importance of the lambda.

It begins with a discussion about how functions are first class values in Lisp. You can pass them around the same way you do any other variable (presumably you can edit them as well... (cdr #'myfunc) being the list of parameters perhaps? But now I'm talking about things I don't know...). This is well and good and useful. You can pass them on to higher order functions all over the place if need be.

To come back to lambda, the special form is

lambda is a macro, not a function, and returns an anonymous function (not a macro, or a llama). Because lambda is a macro it doesn't evaluate all of its parameters prior to execution, so the {code} passes in unaltered (I assume anyway) by the parser.

I suppose what I'm failing to understand is how this is more useful than, say, constructing an actual function (if you need it more than once) or simply placing code inline. For example:

Is functionally equivalent to

and

(I suppose both of those are really the same solution, one just explicitly recurses where the other lets mapcar deal with that complexity) Once I've defuned a function I can use it in multiple places. A lambda function is, by virtue of its anonymity, incapable of such feats (unless, again, I'm missing something?).

Now that I try to think about it though, there doesn't seem to be a C-like loop structure in Lisp. Not that I've gotten to yet anyway. If there is you should be able to simply put the (/ x 2) inside the loop directly. (Edit: There is, it's in the next chapter!)

Now, is the lambda code above 'cleaner'? That depends. A neophyte would probably say 'no'. The mapcar snippet is nearly as concise and more human readable (which is desirable) to a beginner. A programmer steeped in Lisp will, apparently, disagree.

Then of course there's the near-mysticism that the author gets into about Lisp growing out of lambda calculus and how it's really sort of the only function in Lisp, etc. Which is great if you live in an ivory tower and get a stipend for getting other people's brains in knots (especially if you still appear to know what you're talking about). Unfortunately, I don't see (yet?) how this makes Lisp superior to other languages. But. This is the first brush with it and clearly there's something here if the amount of ink spilled on it is any indication. So hopefully understanding will come shortly.

Friday, June 22, 2012

Land of Lisp chapter 5

Chapter 5 is exciting. We get to actually write a bit of an engine (if that's not glorifying it too much) for a text adventure game. Okay, it's 3 rooms and 4 objects and no interactions to speak of yet. That's not the good part. More content can be added easily enough by extending the global variables. But I'm getting ahead of myself.

One language syntax that was introduced is quasiquoting. Basically this is a syntax that allows you to embed bits of code inside a data list. This is familiar to me since I work with a scripting language that does this by default. In Lisp

notice the backtick instead of single quote. That indicates quasiquoting 'mode' (not sure mode is the right term in the same way it applies to data/code mode but whatever). The comma indicates the beginning of a code block and Lisp automatically returns to data mode once the list closes. In this case I could have left the parentheses around foo off, but I left them in to make the end of code mode more explicit.

In the builtin scripting language for UC4

So this might have been a concept unique to Lisp(s) once upon a time, but no longer.

The second bit of syntax is the use of #' to indicate that the following symbol is a function name. This is necessary because Common Lisp maintains separate namespaces for variables and functions. Apparently this means it is called a Lisp-2 language. This in comparison to Scheme which, as a Lisp-1 language, maintains a single namespace containing both functions and variables. So you couldn't have a variable named car in Scheme (car is a standard builtin function in Lisp, I assume it is in Scheme as well?).

There is also some more discussion of functional programming but that isn't why I'm working through this so I'm not going to spend more time on it.

This chapter also introduces the conceptual architecture for the Wizard's Adventure Game and constructs a good bit of basic functionality. We view the game as a mathematical graph; each room is a node and the paths between them are edges in the graph. Why this particularly matters enough to bleed ink on I don't rightly know but I'm not a game designer (yet?). It's as good as any visualization and probably better than some.Using the parlance of nodes and edges we proceed to build the tables for rooms and the paths between those rooms as global variables.

I'll link to the full (and developing, I'm not going to keep versions for each chapter) code for the game at the bottom. In the code above we have a pair of associative array... er, lists describing the nodes and the vital information for the paths. We also build a series of functions to pull out the specific room information. These functions (which I'm not going to bother copying in here, download the source if you're curious) use the assoc function to retrieve a specific element from the associative list.

which we can then pull the description from. We also created a list of objects and a list defining where those objects are located.

We also used the append function to join lists together. This is conceptually equivalent to string concatenation except it applies to lists. We used append in conjunction with apply basically to flatten out nested lists created by mapcar. mapcar is what's called a higher-order function because it takes another function as a parameter and does something with it. In this case, the function is executed against each item in a list

and the returns are consed together into a unified list.

The apply function is also higher-order and it takes a list of inputs and feeds them one piece at a time to the function parameter. This is a convenient way to remove a layer of nesting from a list, but I don't entirely grok the logic. I'll need to feel this one out some more.

In this case we apply-ed the append function to the nested lists created by mapcar to get a flat list of symbols that reads like text. One thing I forgot to discuss at the top is the deliberate use of symbols instead of strings. This isn't imposed by the language, but the language makes it much easier to work with lists of symbols instead of strings, apparently. We could certainly use the string data type for this, but then functions like cadr would work differently on them and would require more code.

We then proceed to take all these things and build a rudimentary user interface. Functions are defined for look, walk, and pickup. Of these, only pickup is really interesting; it uses push to add a variable to the front of the object locations associative list with the value of body. Since assoc only returns the first item in the list that matches this effectively hides the original entry and the item now is only visible in inventory (also a function built at the end of the chapter).

Here's the link to the code as it currently exists. Bear in mind that this will be built upon further in later chapters and I'm not going to bother keeping multiple copies. If you want chapter-by-chapter code buy the book.

Monday, June 18, 2012

Land of Lisp Chp 4

Chapter 4 covers exclusively boolean operations. It starts with a discussion of the only false data value in Lisp which is the empty set '(). This differs from Scheme, though the details of that aren't discussed as they're clearly outside the scope of the book. Note that it is represented in data mode because it is a data value, not a form.

To complicate matters (which seems to happen a lot in this chapter) '() isn't the only way to represent falsehood. This is a careful distinction which I'll come back to. The following are all false in Lisp

The first is just the empty list. The second resolves to an empty list due to the way Lisp parses forms. nil is actually a constant that resolves to 'nil and part of the Common Lisp spec is that 'nil and '() are equivalent. Why are all 4 deliberately set up this way? The book doesn't say. I suspect backwards or cross-dialect compatibility, but to be honest I don't really care right now. It is what it is, as my boss is fond of saying. The important thing is that an empty list is false, and any list that is not empty is true by definition (though in practice the 'nil can present some gotchas that will come up later). This lends Lisp to easy recursive processing of lists like so.

The above recursively cdrs to the end of the list and adds 1 for each symbol; the false branch of the if form returns 0 for the empty list at the end

Next up is if. Which has already been used but not discussed. It's hard to talk about boolean operations without 'if' in seemingly any language. Lisp's if is a bit stunted compared to something like a dialect of C. if only does one thing. Because of the way the command is structured

you can only evaluate one list. Which is a tad misleading since that one list could be a function form that does a million things or, as the book suggests, a call to progn which is glossed over here but apparently behaves similarly to an eval function. Still, it's an important thing to remember and it would tend to reinforce functional programming if that's your thing.

A key feature of if is that, like many other languages, it performs short circuit evaluation. The book spends a lot of ink on this, but I shan't bother except to say that if can do this because it is a special form as opposed to other forms which evaluate all their parameters. This is glossed over here as well as macros which are apparently similar. This will come up again in chapter 16 it seems.

There are a number of alternatives to if. when and unless are mirror siblings.

when executes its commands if {boolean} is true and, as might be guessed, unless executes its commands if {boolean} is false. These each will take an command list of arbitrary length. Both return nil and do nothing if {boolean} is not the correct value.

Finally there are 2 conditional functions that are fully flexible. I almost said functional but while the prior conditionals have been somewhat less flexible than the conditionals of other languages it's worth noting that they're easy to understand and read, and are largely self documenting. These two, on the other hand, are more like another language's switch/case statement, are complex to read (lots of syntax which, in Lisp, is parentheses and hard for an unpracticed human eye to track) and not very self-obvious. They can be formatted to be easier to read and written to be, or the surrounding code architected to be, easier to grok but there's a limit to how much that can accomplish. The book mentions none of that and perhaps I'm just suffering from a neophyte's inadequacies; it is mentioned that seasoned Lispers prefer cond because of it's generality. I don't know, but without further ado however here is the cond and case functions.

Clearly these two can quickly become hard to read. Nevertheless they're probably called for in some circumstances. cond takes a what is basically a list of when forms. The first matching {boolean} is executed and the remainder ignored. As one might expect the final {boolean} is often a true value to drive default behavior. case is nearly a C style switch statement. It takes a {symbol} which it will compare to the various {value}s defined in its body using (specifically) the eq function (this will have more meaning in a minute) and executes only the matching branch. It isn't stated explicitly but the otherwise branch is default behavior.

There are 2 boolean operator functions of note. and ... and... or. These each take a list of parameters and return a boolean based on the boolean evaluation of those parameters much like you would expect. There is an interesting side effect of the short circuit operation of these functions. Take the following example (ripped straight from the book).

In the above form the 3 parameters are fed to and. You could imagine this being called when an editing program is closed. First the *file-modified* variable is tested and if it's false and immediately returns nil. If it's true then the function (ask-user-about-saving) is tested. Presumably this takes input from the user. If the user inputs a value that is evaluated to true then the (save-file) function is executed. In theory this would return a success/failure variable which would then determine whether and returns nil or true. All of that in one little line. That's some pretty dense semantics. It might be better to use a more verbose if structure if the code needs to be maintained by neophytes since all of the relies on some subtle effects. Personally, I like the density and this case isn't terribly difficult to figure out. Maybe it's just because I grok short circuit evaluation, I dunno.

In a slight tangent the book interjects that one subtlety of the Lisp definition of false is that functions get a freebie return value. Anywhere that a function could return truth or falsehood it would be better to find some more useful value to return than just true; if you're testing whether a variable is defined you might as well return the value (unless it's nil!) since it will be evaluated as true regardless of the actual value. The book uses the member and find-if functions to discuss this but I'm not going to get into them since this is already long and I want to move on to chapter 5.

Finally we come to the equality functions. The book discusses 6 commonly used equality functions. Yes, 6! equal, eql, eq, =, string-equal, and equalp. The rule of thumb is to use eq to compare symbols (it's fast, efficient, and doesn't work well on things that aren't symbols) and to use equal for everything else. I don't have the gumption to dig far into equality comparison right now but will point out that equalp will handle case insensitive string comparisons as well as comparing integers to floating point values.

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.