Ex5.4〜Ex5.6 ELIZAの改良問題

ELIZAの改良問題を3つ

;; Exercise 5.4 [s] We mentioned that our version of ELIZA cannot
;; handle commas or double quote makes in the input. However, it seems
;; to handle the apostrophe in both input and patterns, Explain.

commaやdouble quoteが扱えないのは、readに特殊文字として解釈されてしまうからですね。 '(アポストロフィー)を扱えているのは、これもreadがquoteに置き換えているからです。

(hoge's) => (hoge (quote s))

Ex5.4を受けて、Ex5.5,Ex5.6では以下の4つの改良をします。

  1. 区切り文字を入力出来るようにする
  2. ()を入力しないですむ様にする
  3. Abortしないで終了出来るようにする
  4. 出力から()をとる
;; Exercise 5.5 [h] Alter the input mechanism to handle commas and
;; other punctuation characters. Also arrange so that the user doesn't
;; have to type parentheses around the whole input expression. (Hint:
;; this can only be done using some Lisp functions we have not seen
;; yet. Look at read-line and read-from-string.)

;; Exercise 5.6 [m] Modify ELIZA to have an explicit exit. Also
;; arrange so that the output is not printed in parentheses either.

(in-package :eliza)

(defparameter *eliza-punctuation-char*
  '(#\{ #\} #\( #\) #\, #\. #\' #\` #\" #\' #\# #\\ #\;)) ;"

(defun eliza-escape-punctuation-char (string)
  (substitute-if #\space #'(lambda (c)
			     (member c *eliza-punctuation-char*)) string))
					 
(defun eliza-read ()
  (let ((s (make-string-output-stream)))
    (write-string "(" s)
    (write-string (eliza-escape-punctuation-char (read-line)) s)
    (write-string ")" s)
    (read-from-string (get-output-stream-string s))))

(defun eliza-print (list &rest rest)
  (declare (ignore rest))
  (format t "~@(~{~s ~}~)~%" list))

(defun eliza ()
  "パターンマッチを使って、ユーザのインプットに答える。"
  (loop 
     (print 'eliza>)
     (let ((input (eliza-read)))
       (cond ((eq (car input) 'quit) (return))
	     (t
	      (eliza-print (flatten (use-eliza-rules input))))))))

上記のように作ってみましたが、PAIPのAnswersの方が綺麗です。
Answersを見て学習したこと。

  1. 文字列(というかシーケンスならなんでも)の結合にはconcatenateが使える
  2. 文字列に対してもfindできる

シーケンスに適用できる関数は汎用性が高いですね。更なる学習が必要です。