章學習範例: * (setf temperature 100) * (print temperature) 100 ;PRINT's printing action does this. 100 ;This is the value of the PRINT form. --------------------------------------------------------- * (if (< -1 (print (- temperature 98.6)) +1) ;Print a value. 'normal 'abnormal) 1.4 ;Value printed by PRINT form. ABNORMAL ;Value returned by IF form. --------------------------------------------------------- * (setf name 'kirsh symptoms '(fever rash nausea)) * (print (list 'patient name 'presented (length symptons) 'symptons symptoms)) (PATIENT KIRSH PRESENTED 3 SYMPTOMS (FEVER RASH NAUSEA)) ;Side effect. (PATIENT KIRSH PRESENTED 3 SYMPTOMS (FEVER RASH NAUSEA)) ;Value. --------------------------------------------------------------- * (read)kirsh KIRSH ---------------------------------------------------------- * (let ((p nil)) ;P's initial value is NIL. (print ;Prompt. '(please type a patient name)) (setf p (read)) ;Get name from user. (print (append '(ok the name is) ;Compose and print message. (list p))) p) ;Final form inside LET is P. (PLEASE TYPE A PATIENT NAME) Kirsh ;Prompt plus user's response. (OK THE NAME IS KIRSH) ;Acknowledgement message. KIRSH ;The value returned by the LET. -------------------------------------------------------------- * (format t "Hello!")Hello! ;Format prints Hello! NIL ;Format's value is NIL. ----------------------------------------------------------- * (format t "~%Hello!") Hello! ;FORMAT prints Hello! NIL ;FORMAT's value is NIL. * (format t "~%Hello!~%I'm ready to start now.") Hello! ;Printed by FORMAT. I'm ready to start now. ;Printed by FORMAT. NIL ;FORMAT's value. -------------------------------------------------------------- * (progn (format t "~%Line followed by % sign directive.~%") (format t "~%Line preceded by % sign directive.~%") (format t "~&Line preceded by & sign directive.")) Line followed by % sign directive. ;Concluding % sign directive. ;Preceding % sign directive. Line preceded by % sign directive. ;Concluding % sign directive. Line preceded by & sign directive. ;Preceding & sign directive. NIL -------------------------------------------------------------- * (format t ;Print on your terminal. "~%The next patient is ~a." ;An A directive appears. name) ;The A's matching argument. The next patient is KIRSH. ;Side effect. NIL ;Value. ---------------------------------------------------------------- * (format t "~%Patient ~a presented ~a symptoms ~a." name ;Argument for first A. (length symptoms) ;For the second A. symptoms) ;For the third A. Patient KIRSH presented 3 symptoms (FEVER RASH NAUSEA). ;Side effect. NIL ;Value. ---------------------------------------------------------------- * (format t "~%Patient: ~10aSymptoms: ~a" name (length symptoms)) Patient: KIRSH Symptoms: 3 ;Ten characters in KIRSH plus spaces. NIL ;The value returned. 題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題 9-1: In a previous problem in chapter 5, you defined TOWER-OF-HANOI, a procedure which counts the number of moves required to move a stack of disks from one pin to another under the following conditions: * Only one disk can be moved at a time. * The disks all have different diameters, and disk can ever be placed on top of a smaller one. * Initially all disks are on one pin and each disk rests on a larger one. The official solution, expanded abit so as to pass along the names of pins involved in the moves, looks like this: (defun tower-of-hanoi (disks from to spare) (if (endp disks) 0 (+ (tower-of-hanoi (rest disks) from spare to) 1 (tower-of-hanoi (rest disks) spare to from)))) Now the problem. Modify TOWER-OF-HANOI so that it prints a series of instructions for moving disks, rather than counting the number of moves, as in the following example: * (tower-of-hanoi '(3 2 1) 'a 'b 'c) Move 1 from A to B. Move 2 from A to C. Move 1 from B to C. Move 3 from A to B. Move 1 from C to A. Move 2 from C to B. Move 1 from A to B. NIL --------------------------------------------------------------------- ((David Kirsh) (fever rash)) ((Gerog Hegel) (fever headache)) ((Immanuel Kant) (nausea)) ((Rene Descartes) (nausea)) ((Jean-Paul Sartre) (nausea stomachache)) -------------------------------------------------------------- (with-open-file (<stream name> <file specification> :direction <:input or :output>) ...) ------------------------------------------------------------------ (with-open-file (<stream name> <file specification> :direction :input) ... (read <stream name>) ...) ----------------------------------------------------------- (with-open-file (patient-stream "/phw/lisp3/patients.lsp" :direction :input) ...) -------------------------------------------------------------- * (with-open-file (patient-stream "/phw/lisp3/patients.lsp" :direction :input) (dotimes (n 2) (print (read patient-stream)))) ((DAVID KIRSH) (FEVER RASH)) ;First expression read. ((gEORG hEGEL) (FEVER HEADACHE)) ;Second expression read. NIL -------------------------------------------------------------- * (with-open-file (patient-stream "/phw/lisp3/patients.lsp" :direction :input) (do ((patient (read patient-stream nil) (read patient-stream nil))) ((not patient)) (print patient))) ((DAVID KIRSH) (FEVER RASH)) ((GEORG HEGEL) (FEVER HEADACHE)) ((IMMANUEL KANT) (NAUSEA)) ((RENE DESCARTES) (NAUSEA)) ((JEAN-PAUL SARTRE) (NAUSEA STOMACHACHE)) NIL --------------------------------------------------------------- (with-open-file (<stream name> <file specification> :direction :output) ... (print <expression whose value is to be printed> <stream name>) ...) --------------------------------------------------------------- (defun nauseated-p (description) (member 'nausea (second description))) * (with-open-file (patient-stream "/phw/lisp3/patients.lsp" :direction :input) (with-open-file (nausea-stream "/phw/lisp3/nausea.lsp" :direction :output) (do ((patient-description (read patient-stream nil) (read patient-stream nil))) ((not patient-description)) (when (nauseated-p patient-description) (print patient-description nausea-stream))))) NIL -------------- ((IMMANUEL KANT) (NAUSEA)) ((RENE DESCARTES) (NAUSEA)) ((JEAN-PAUL SARTRE) (NAUSEA STOMACHACHE)) 題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題 9-2: Sometimes NIL can appear in a file. In such situations, (READ <input stream> NIL) could return NIL before encountering the end of a file, promoting confusion and error. To avoid this confusion and error, you can supply still another optional argument that is returned on encountering the end of a file. Many programmers use EOF for end-of-file: (read patient-stream nil 'eof) Show how to print out all the patient records in the patient description file using a READ from which an EOF argument. ------------------------------------------------------------ 9-3: In chapter 6, five book descriptions were combined into one list assigned to BOOKS: (setf books (list (make-book '(artificial intelligence) '(patrick henry winston) '(technical ai)) (make-book '(common lisp) '(guy l steele) '(technical lisp)) (make-book '(moby dick) '(herman melville) '(fiction)) (make-book '(tom sawyer) '(mark twain) '(fiction)) (make-book '(the black orchid) '(rex stout) '(fiction mystery)))) You would never type such an expression directly into LISP for two reasons: first, you could not expect to type so much without mistakes; and second, you want a permanent bibliography, not one that will vanish when you terminate your session with LISP. Consequently, it is much more natural to create a file in which the SETF form is the sole contents. Reading from the file, using LOAD, would assign the list of book descriptions to BOOKS. Usually it is better to put just the book descriptions in the file without the SETF, just as in the patient-descriptions example. Explain why. ---------------------------------------------------------------- 9-4: FORMAT also can print to output streams. You need only replace the T with an output stream name. Show how you would create a file containing the following, given the usual patients in the patients file: Patient 1 is not nauseous. Patient 2 is not nauseous. Patient 3 is nauseous. Patient 4 is nauseous. Patient 5 is nauseous. ----------------------------------------------------------------- * (setf form-to-evaluate '(+ 2 2)) ;Variable's value is assigned. (+ 2 2) * form-to-evaluate ;Variable's value is a form. (+ 2 2) * (eval form-to-evaluate) ;Variable of that form is a number. 4 --------------------------------------------------------------------- * (read)(+ 2 2) ;You type (+ 2 2) for READ. (+ 2 2) ;READ returns (+2 2) * (eval (read))(+ 2 2) ;You type (+ 2 2) for READ. 4 ;EVAL evaluates READ's result. 題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題題 9-5: Define ECHO1, a procedure that reads expressions and returns them without evaluation, and define ECHO2, a procedure that returns with evaluation: ------------------------------------------------------------------ * (length '(a b c)) 3 * (length "abc") 3 * (reverse '(a b c)) (C B A) * (reverse "abc") "cba" ---------------------------------------------------------------- * (elt '(a b c) 0) A * (elt '(a b c) 2) C * (elt "abc" 0) #\a * (elt "abc" 2) #\c --------------------------------------------------------------- * (string= "abc" "xyz") NIL * (string= "abc" "abc") T * (string= "abc" "ABC") NIL * (String-equal "abc" "xyz") NIL * (string-equal "abc" "abc") T * (string-equal "abc" "ABC") T -------------------------------------------------------------------- * (char= #\a #\b) NIL * (char= #\a #\a) T * (char= #\a #\A) NIL * (char-equal #\a #\b) NIL * (char-equal #\a #\a) T * (char-equal #\a #\A) T ------------------------------------------------------------- * (search "Katz" "Katz, Boris") 0 * (search "Boris" "Katz, Boris") 6 * (search "Pushkin" "Katz, Boris") NIL ------------------------------------------------------------- * (search "BORIS" "Katz, Boris") NIL * (search "BORIS" "Katz, Boris" :test #'char-equal) 6 ----------------------------------------------------------- * (search '(Katz) '(katz boriz)) 0 * (search '(boris) '(katz boris)) 1 * (search '(pushkin) '(katz boris)) NIL ---------------------------------------------------------- * (read-line)This is a READ-LINE test. "This is a READ-LINE test." NIL * (read-char)x #\x * (read-char)X #\X ----------------------------------------------------------- Horn, Berthold 5863 BKPH Katz, Boris 6032 BORIS Winston, Patrick 6754 PHW Woven Hose Cafe 577-8444 ----------------------------------------------------------- (defun fetch (fragment file) (with-open-file (line-stream file: direction :input) (do ((line (read-line line-stream nil) (read-line line-stream nil))) ((not line) (format t "~%No such entry!")) (when (search fragment line:test #'char-equal) (format t "~%~a" line) (return t))))) ------------------------------------------------------------ * (fetch "Katz" "people.ail") Katz, Boris 6032 BORIS T * (fetch "Pushkin" "people.ail") No such entry! NIL 解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解解 9-1: (defun tower-of-hanoi (disks from to spare) (unless (endp disks) (tower-of-hanoi (rest disks) from spare to) (format t "~%Move ~a from ~a to ~a." (first disks) from to) (tower-of-hanoi (rest disks) spare to from))) Note that the placement of the FORMAT form between the two recursive calls to TOWER-OF-HANOI is important because the instruction to move the bottom disk must be given after the instructions for moving all but the bottom disk to the spare pin. Similarly, the instruction to move the bottom disk must be given before the instructions for moving the disks back from the spare pin to the destination pin. -------------------------------------------------------------------------- 9-2: * (with-open-file (patient-stream "/phw/lisp3/patients.lsp" :direction :input) (do ((patient (read patient-stream nil 'eof) (read patient-stream nil 'eof))) ((eq patient 'eof)) (print patient))) -------------------------------------------------------------------------- 9-3: Data base files are often large to huge. Under such conditions, it is better to read individual descriptions from a file, rather than forming a long list of descriptions that would consume too much random-access memory. ------------------------------------------------------------------------- 9-4: (with-open-file (patient-stream "/phw/lisp3/patients.lsp" :direction :input) (with-open-file (nausea-stream "/phw/lisp3/nausea.lsp" :direction :output) (do ((patient-description (read patient-stream nil) (read patient-stream nil)) (n 1 (+ 1 n))) ((not patient-description)) (format nausea-stream "~%Patient ~a is ~a." n (if (nauseated-p patient-description) "nauseous" "not nauseous"))))) NIL --------------------------------------------------------------- 9-5: (defun echo1 () (loop (print (read)))) (defun echo2 () (loop (print (eval (read)))))