Note that linefeeds are ignored by lisp. They serve only to make the code more readable.
Almost all lisp ops are functions (i.e., return a value)
The QUOTE operator (abbreviated with the apostrophe "'") suspends evaluation of the next expression. In other words, QUOTE is a function that returns its argument directly, i.e., without first evaluating it. As noted above, most functions are invoked only after first evaluating their arguments. QUOTE is a special function, meaning that it is invoked without first evaluating its argument. There are several special functions in Lisp. symbols lisp programs are, themselves, lists!
All lists can be composed via a sequence of cons cells. Example: (A (B C) D) is (cons a (cons (cons 'b (cons 'c nil)) (cons 'd nil)))
Reading Lisp -- indentation and parentheses. Should be handled by your editor. Commercial lisp systems provide such editors. Emacs is one of the best, and is free. See the notes on the class Web pages.
(print "comment with a semicolon ; is fine") ; A comment
(setq mynewvar 5)
Generally, it is poor form to introduce variables this way. Instead, use DEFVAR to define global variables, and LET to define variables local to individual functions:
(DEFVAR mynewvar 5) ; My new variable is defined here
SETQ is normally used for setting the values of variables.
SETF is used in conjunction with accessors, to set l-values, much like pointers are used in C++. For example,
(setf (car x) 'a)is used to set the CAR of x to a. So if X is (1 2 3), then that setf would change X to be (A 2 3).
Pointers are ubiquitous and implicit in Lisp, unlike most other programming languages, such as C. This leads to real flexibility in using the language. On the other hand, it also creates the need for garbage collection, because the user is not responsible for dynamic memory management. (I.e., no MALLOC or FREE in Lisp.)
(defun name-of-function (arg1 arg2 ...) s-exp1 s-exp2... )where arg1 arg2 ... are the formal parameters to the new function. The value returned by a function is the value of the last s-expression of the function, or that returned by a RETURN form.
(setf (symbol-function 'sum) (lambda (x y) (print "two argument summation") (+ x y)))
(atom 'a) (atom '( 1 2 3)) (listp '(1 2 3)) (atom nil) = (listp nil) = (null nil) CONSP == LISTP except for NIL (equal '(a b c) (list 'a 'b 'c))
There are other equality predicates, but EQUAL is most general. True if two things print the same. EQ is "pointer equality". (EQ A B) iff A and B point to the same object.
zerop, oddp, <, <=, !=
(typep 6 'number) (member 'b '(a b c)) ;; Doesn't just return T, since any non-NIL connotes true, and this is more informative. (member 'b '(a (b) c))
ifCOND is a function, returning val of 1st term evaling to non NIL. Similar to C's CASE statement.[ ] (cond ((listp x) (car x)))
(defun car-atomp (x) (cond ((listp x) (atom (car x)) (t nil))) ; If this is omitted, still returns NIL (by def of COND) but this ; is more clear-cut. (cond ((= x 5) (setq z 3)) (t (setq z 4)))is completely equivalent to
(if (= x 5) (setq z 3) (setq z 4))
(if (= x 5) (print "X is") (print 5))which is analagous to the C++ IF statement:
if (x == 5) cout << "X is"; cout << 5;Instead use
(if (= x 5) (let () (print "X is") (print 5)))which is analogous to the C++ code:
if (x == 5) { cout << "X is"; cout << 5; }We talk more about LET later.
(or (= x 4) (not (numberp x)) (setq x 5))is functionally equivalent to:
(if (and (not (= x 4)) (numberp x)) (setq x 5) t) (and (setq x 4) (not (numberp x)) (setq x 5))
> (defun wow (x) (setq x 5) (bow) (print x)) WOW > (defun bow () (setq x (* 2 x))) ;; x is a FREE variable, here, at definition time. BOW > (wow 2) >>Error: The symbol X has no global value SYMBOL-VALUE: Required arg 0 (S): X > (setq x 4) ; defines x at top level (i.e., globally) 4 > (wow 2) 5 5 > x 8 > (wow 2) 5 5 > x 16 >
**DANGER, special variables ahead....***
> (defun wow (x) (declare (special x)) (setq x 5) (bow) (print x)) ;; Because WOW's X is "special", references to symbol x within the time that WOW ;; is executing will refer to the x defined in WOW's scope. In effect, WOW's x ;; "intercepts" references to "global" variable x. > (wow 2) 10 10 ;; Notice that the value of the "toplevel" x has not changed.... > x 16 >Here is another example of dynamic scoping. We are writing a function, FIND-BIGGEST, that takes a list of positive integers, and returns a dotted pair consisting of the biggest and second-biggest integers in the list. For our first attempt, we'll use a global variable (boo, hiss!). FIND-BIGGEST uses REDUCE in conjunction with another function I wrote, BIGGESTYET and a global variable.
(defvar second-biggest -1) ; This global is used in BIGGESTYET ;;; FIND-BIGGEST (L) Returns a dotted pair: the largest integer in L (a list ;;; of positive integers) and he second largest integer in L. (defun find-biggest (L) (setq second-biggest -1) ; Takes care of multiple runs of FIND-BIGGEST (let ((result (reduce #'biggestYet L))) (cons result second-biggest))) (defun biggestYet (a b) (let ((max (if (< a b) b a)) (min (if (>< a b) a b))) (if (> min second-biggest) (setq second-biggest min)) max)) USER(20): (find-biggest '(1 3 8 5 2 6 2)) (8 . 6)Now, we will use dynamic scoping (a SPECIAL variable) to solve the same problem without a global variable. In effect, secondB is like a "temporary" global variable, that exists only within the lifetime of FIND-BIGGEST.
(defun find-biggest (L) (let ((secondB -1)) (declare (special secondB)) (let ((result (reduce #'biggestYet L))) (cons result secondB)))) (defun biggestYet (a b) (let ((max (if (< a b) b a)) (min (if (< a b) a b))) (if (> min secondB) (setq secondB min)) max))