List operations
Jul 24th, 2009 by james
The other day Eddie was lamenting that certain Ginger list operations were confusing to read. Patterns like (tail (tail x)). This is a standard gripe in Scheme and Lisp. The same operation in Scheme is (cdr (cdr x)) which I dare say is even less readable but at least can be shortened to (cddr x).
Another common pattern in Scheme is (cadr x), (caddr x), (cadddr x), etc. which yields the second, third and fourth terms in a list respectively. In Ginger, I have renamed these operations (second x), (third x), (fourth x) etc. But as Eddie points out (cddr x), (cdddr x), (cddddr x) is another common pattern. At least it’s very common in my code. In Ginger that translates to (tail (tail x)), (tail (tail (tail x))) and (tail (tail (tail (tail x)))) respectively.
Since that’s pretty unreadable I’ve decided to come up with a better name. The first thing I realized is what I’m really interested in the Nth cons cell in a list. So maybe we should say second-cons, third-cons, fourth-cons? That’s better but wordy. It also deemphasizes that what we are getting in return is itself a list. The naming solution I finally arrived at is (second* x), (third* x), (fourth* x). (Note that the asterisk doesn’t have the same connotation it does in Scheme.)
I really like this because it’s apparent that (second* x) and (second x) are related. One is a cons cell and the other is the value in the first part of the cell. That is, (second x) = (first (second* x)). This naming convention also allows me to rename the hideously named function (last-cons x) to (last* x).
A seasoned Scheme programmer will note that cons cells can be used to represent more than just lists, so the more abstract car and cdr names are appropriate in that they emphasize the relationships of the cons cells rather than their application. The Scheme naming mechanism is not without merit but Ginger’s philosophy tends to be very utilitarian – most of the time cons cells make up lists and we’d like the language for manipulating and referencing lists to be very clear.
Now, since (second* x) and (tail x) are the same thing should I remove tail? I may try it out and see how it reads.