Lisp中的简单用户输入函数与复杂用户输入函数

Lisp中的简单用户输入函数与复杂用户输入函数,lisp,common-lisp,Lisp,Common Lisp,在该站点:有如下用户输入功能: (defun prompt-read (prompt) (format *query-io* "~%~a: " prompt) (force-output *query-io*) (read-line *query-io*)) 与以下更简单的形式相比,上述功能是否有任何主要优势: (defun prompt-read2 (prompt) (format t "~%~a: " prompt) (setf answer (

在该站点:有如下用户输入功能:

(defun prompt-read (prompt)
    (format *query-io* "~%~a: " prompt)  
    (force-output *query-io*)
    (read-line *query-io*))
与以下更简单的形式相比,上述功能是否有任何主要优势:

(defun prompt-read2 (prompt)
    (format t "~%~a: " prompt)
    (setf answer (read-line)))

建议始终使用
强制输出
*查询io*
吗?

是的,您编写代码很简单,但第一个更清楚您在做什么:

*query io*是一个包含输入流的全局变量(您可以通过全局变量的*命名约定来判断) 连接到终端。提示读取的返回值将是 最后一个表单的值,即对READ-LINE的调用,它返回 读取的字符串(不带尾随换行符。)

这就是他们所说的*查询io*

关于可以放在那里的流,工作如下:

大多数其他I/O函数也接受T和NIL作为流指示符 但有不同的含义:作为流指示符,T表示 双向流*终端-IO*,而NIL指定 *标准输出*作为输出流,标准输入*作为输入流


在这种情况下,这似乎只是指向*标准输入*而不是双向流t

设置这样的全局变量的答案是错误的。你只需返回答案,让来电者随心所欲。如果确实使用特殊(~global)变量,则应在名称周围加星号(
*ANSWER*
而不是
ANSWER

FORCE-OUTPUT
需要确保用户在回答问题之前看到提示。如果我在终端中使用SBCL运行第二个版本,程序就会冻结,等待输入而不说任何话

*QUERY-IO*
应该用于从用户查询内容,因为某些环境可能希望以不同于其他输出的方式处理这些内容。例如,可能有人为您的程序编写GUI包装器,将查询转换为图形对话框。或者,他们可能希望将其作为脚本的一部分运行,提供来自字符串的输入

(defun prompt-read (prompt)
  (format *query-io* "~%~a: " prompt)  
  (force-output *query-io*)
  (read-line *query-io*))

(defun hello ()
  (format t "~&Hello ~a!~%" (prompt-read "What's your name")))

(defmacro with-input ((input) &body body)
  `(let ((*query-io* (make-two-way-stream (make-string-input-stream ,input)
                                          (make-string-output-stream))))
     ,@body))

(defun test ()
  (with-input ("jkiiski")
    (hello))
  (with-input ("rnso")
    (hello)))
(test)
; Hello jkiiski!
; Hello rnso!
编辑

使用SBCLs灰色流的更复杂示例

(defclass foo-stream (sb-gray:fundamental-character-input-stream)
  ((output-input-script :initarg :script :accessor foo-stream-script)
   (output-stream :initarg :out :accessor foo-stream-out)
   (current-input :initform nil :accessor foo-stream-current-input)))

(defmethod sb-gray:stream-read-char ((stream foo-stream))
  (with-accessors ((input foo-stream-current-input)
                   (out foo-stream-out)
                   (script foo-stream-script)) stream
    (when (or (null input)
              (not (listen input)))
      (let ((output (string-trim '(#\space #\newline)
                                 (get-output-stream-string out))))
        (setf input (make-string-input-stream
                     (format nil "~a~%"
                             (cdr (assoc output script :test #'string=)))))))
    (read-char input)))

(defun prompt-read (prompt)
  (format *query-io* "~%~a: " prompt)  
  (force-output *query-io*)
  (read-line *query-io*))

(defun hello ()
  (format t "~&Hello ~a!~%" (prompt-read "What's your name"))
  (format t "~&I'm ~a too!" (prompt-read "How are you"))
  (format t "~&~a~%" (if (string-equal (prompt-read
                                        "Do you want to delete all your files")
                                       "yes")
                         "Deleting all files... (not really)"
                         "Not deleting anything.")))

(defmacro with-input-script ((script) &body body)
  (let ((out-sym (gensym "out")))
    `(let* ((,out-sym (make-string-output-stream))
            (*query-io* (make-two-way-stream
                         (make-instance 'foo-stream
                                        :out ,out-sym
                                        :script ,script)
                         ,out-sym)))
       ,@body)))

(defun test ()
  (with-input-script ('(("What's your name:" . "jkiiski")
                        ("How are you:" . "great")
                        ("Do you want to delete all your files:" . "No")))
    (hello))
  (with-input-script ('(("What's your name:" . "Foo Bar")
                        ("How are you:" . "fine")
                        ("Do you want to delete all your files:" . "Yes")))
    (hello)))

(test)
; Hello jkiiski!
; I'm great too!
; Not deleting anything.
; Hello Foo Bar!
; I'm fine too!
; Deleting all files... (not really)