Records or structures - bundles of named objects - are ubiquitous in programming languages. A simple example in C might be a struct representing a 2d point.
typedef struct point_tag {
double x, y;
} point;
point p;
p.x = 10;
p.y = 11;
Lisp is a list-based language, and although most modern lisps provide some higher level abstraction for structures or records, it is not uncommon to use simple lists and functions to represent them. There is one very nice feature of this approach which I have identified as a repeated pattern in a lot of my lisp code which uses the fact that lists are the main data type in Lisp to very good effect.
Consider the Lisp approach to the point struct, assuming we don't want to use a built-in structure type and don't have access to something as excellent as CLOS. (This is emacs lisp with (require 'cl) - but probably also Common Lisp).
(defun point! (x y)
(list 'point! x y))
(defun point-x (p)
(cadr p)) ;; return the second element of the list p
(defun point-y (p)
(caddr p)) ;; return the third element of the list p
(defun set-x (p v)
(setf (cadr p) v))
(defun set-y (p v)
(setf (caddr p) v))
(defun point-+ (p1 p2)
(point! (+ (point-x p1) (point-x p2))
(+ (point-y p1) (point-y p2))))
(let ((p1 (point! 3 4))
(p2 (point! 3 3)))
(point-+ p1 p2)) ;; evaluates to (point! 6 7)
What is useful about this is that the default printed representation of our data structure
is the code which, when executed, makes a structurally identical data structure. If you are programming functionally, then structural equality is what you care about 85% of the time anyway. I find this trick useful for working with Emacs because it is easy to insert the result of a calculation into a buffer, where you then may want to put it into other forms to be evaluated later.
I found myself creating this sort of data structure a lot in Emacs Lisp, Common Lisp and Scheme, so I wrote the following Emacs lisp macro to do some of the finger work for me.
(defun bang (sym)
(intern (format "%s!" sym)))
(defun s-cat (sym1 sym2)
(intern (format "%s-%s" sym1 sym2)))
(defun ques (sym)
(intern (format "%s?" sym)))
(defmacro defstruquine (name &rest slots)
(let* ((n-fields (length slots))
(i 1)
(out `(progn
(defun ,(bang name) ,slots
(list ',(bang name) ,@slots))
(defun ,(ques name) (item)
(eq (car item) ',(bang name))))))
(loop for slot in slots do
(setf out
(append out
(list `(defun ,(s-cat name slot) (item) (elt item ,i)))))
(setf i (+ i 1)))
(append out (list nil))))
Which can be used thusly:
(defstruquine person first-name last-name age)
(let ((p (person! "Edward" "Olmos" 61)))
(person-first-name p) ;; is "Edward"
(person-age p) ;; is 62
p) ;; returns (person! "Edward" "Olmos" 61)
Which I think is a small example of why Lisp works so well - you really couldn't do this in any other language without a lot of conceptual overhead.
PS - This is called a struquine because a quine is a program which, when evaluated, prints itself. Check it out on the
wikipedia.