A Lisp Potpourri

Functions, Useful Info, & Tricks

CIS447

 

As one gets used to Lisp, there are some functions which can make life easier.  And there is a bag of tricks every Lisp programmer should have at his disposal.  We already saw the OR and AND tricks.  Here are some other useful functions & tricks.

 

First, read pp. 9-14 of Paul Graham: On Lisp.

 

Variations on if

 

when:

  w When writing a function which has only a “then part” and no “else part”, it makes sense to use a specially designated function for that purpose.

          examples:

(when t 3) ® 3

(when nil 3) ® nil

(when (< 5 3) ‘less) ® nil

(when (< 3 5) ‘less) ® less

 

unless:

  w On the other hand, there are times when you want to execute only the “else part”; i.e., you want to execute code only when the test fails.

          examples:

(unless t 3) ® nil

(unless nil 3) ® 3

(unless (< 5 3) ‘greater) ® greater

(unless (< 3 5) ‘greater) ® nil

 

Useful for program development

 

Commenting:

  w The Lisp comment is marked by a semicolon preceding the comment.  It can occur anywhere on the line; everything following on that line becomes a comment.

Copy the function below, paste it into a file, then load it.  [For some reason, pasting directly into a Clisp session does not work].

          example:

 (defun func (x y)

        ; this illustrates a comment

        (cond ((> x y) 'greater)

                 ((< x y) 1 2 ;rest is lost

;so closing paren is on next line

)

(t 'must-be-equal)

                        ))

 

Checking for errors while loading:

  w A mighty pitfall for writing Lisp programs is the annoying missing or extra parenthesis hidden somewhere in your code.  If your program does not load, it is possible to isolate the offending function by interspersing print statements throughout your file.  Paste the functions below into a file, load the file and identify the location of the two errors in function definition.

          example:

(defun f1 (x) x)

(print "f1 loaded")

(defun f2 (x)

    (cond ((> x 5) t)

             ((< x 7)(+ 5 12))

             (t (* 3 21)))

(print "f2 loaded")

(defun f3 (x)

    (do ((y 1 (1+ y)))

        ((> y x) y)

    ))

(print "f3 loaded")

(defun f4 (x)

    (cond ((> x 5) (+ 21 23))

             ((< x 7) t))

             (t (* 3 21))

    ))

(print "f4 loaded")

(defun f5 (x)

    (if (zerop x) (1- x) (f5 (1- x))

    ))

(print "f5 loaded")

 

Returning (print <value>):

  w Sometimes when debugging a program it is useful to find out exactly what value a function is returning.  But it is important not to interfere with its role in the program.  Since print returns whatever it prints, it is always possible to throw a call to print directly in front of a returned value.

          Paste the code below into a file, load it into Lisp and call the double-list function.  Notice how double still works correctly even though its return value is also printed out.

          example:

(defun double-list (list)

        (cond ((endp list) nil)

                 ((cons (double (first list)) (double-list (rest list))))

        ))

(defun double (x) (print (* 2 x)))

 

trace/untrace:

  w Often a program needs more intense debugging action.  Lisp gives you the ability to print out the values of all arguments going into a function as well as the value returned by that function.  This is done via track.  Just type (track func1 func2 . . . funcn) including as arguments the names of all functions you want to track.  To return to a non-tracking mode, type untrack.

          example:

(defun mult-all (even-list)

        (cond ((endp even-list) nil)

                 ((cons (mult2 (first even-list)(second even-list))

                          (mult-all (cddr even-list))

                 ))

        ))

(defun mult2 (x y) (* x y))

          Copy and paste the two functions above into a file, load into Lisp and then type:

(trace mult-all mult2)

(mult-all ‘(1 2 3 4 5 6 7 8))

 

Special to Lisp

 

mapcar:

  w see: Functions as Arguments.

 

lambda:

  w see: Lambda – the Anonymous Function

 

sort:

  w see: Sorting

 

property lists:

  w see: Property Lists

 

assoc:

  w An association list or alist is a list of lists where the first element of each sublist is a key on which the alist can be searched using the function assoc.  Study the sample run below.

          example:

 

[1]> (setf alist '((a 1)(b 2) (c 3)))

((A 1) (B 2) (C 3))

[2]> (assoc 'a alist)

(A 1)

[3]> (setf alist2 '((a . 1)(b . 2)(c . 3)))

((A . 1) (B . 2) (C . 3))

[4]> (assoc 'b alist)

(B 2)

[5]> (assoc 'a alist2)

(A . 1)

[6]> (assoc 'b alist2)

(B . 2)

[7]> (cadr (assoc 'a alist))

1

[8]> (cdr (assoc 'a alist2))

1

[9]> (setf alist3 '((a 1 2)(b 3 4)(c 5 6)))

((A 1 2) (B 3 4) (C 5 6))

[10]> (assoc 'a alist3)

(A 1 2)

[11]> (cdr (assoc 'a alist3))

(1 2)

[12]> (assoc 'b alist3)

(B 3 4)

[13]> (cdr (assoc 'b alist3))

(3 4)

 

  w Notice that the sublists can be pairs, dotted pairs, triples or lists of any length.  The function assoc gives you the sublist and you need to use the proper combination of cars and cdrs to retrieve the items you are looking for.

          For BBESS, notice that *prompts* is an alist.  And it may be useful to organize your fact base as an alist.  Indeed, the functions getval, getprompt, and getokvals

can all be written using assoc as the basic search mechanism and a combination of cars and cdrs to obtain the item(s) sought.

 

remove-if:

  w Sometimes a Lisp function returns a list containing unwanted values.  We can weed out the unwanted items using remove-if.  Notice that remove-if takes a testing function as its first argument.

          example:

 [17]> (remove-if #'evenp '(1 2 3 4))

(1 3)

[18]> (remove-if #'null '(a b nil c nil d nil))

(A B C D)

[19]> (remove-if #'not '(a b nil c nil d nil))

(A B C D)

[20]> (defun true (x)(not (not x)))

TRUE

[21]> (remove-if #'true '(a b nil c nil d nil))

(NIL NIL NIL)

[22]> (defun true (x) x)

TRUE

[23]> (remove-if #'true '(a b nil c nil d nil))

(NIL NIL NIL)

[24]> (true 5)

5

[25]> (true 'x)

X

[26]> (defun true (x)(not (not x)))

TRUE

[27]> (true 5)

T

[28]> (true 'x)

T

[29]> (true nil)

NIL