第玖章學習 Lisp 3rd Edition, Winston & Horn

LISP程序设计案例
本文通过多个示例展示了LISP语言的基本用法,包括条件判断、变量赋值、文件操作等,并提供了塔式汉诺伊问题的解决方案及其它实用程序的设计。
章學習範例:

* (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)))))

转载于:https://my.oschina.net/chuangpoyao/blog/39444

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值