2016-07-11 5 views
-1

Auf dieser Seite: http://www.gigamonkeys.com/book/practical-a-simple-database.html gibt es Funktion Benutzereintrag wie folgt aufgeführt:Einfache vs komplexen Benutzereingabefunktionen in Lisp

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

Sind alle großen Vorteile der oben genannten Funktion es im Vergleich zu einfacherer Form folgt vor:

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

Wird empfohlen, die ganze Zeit force-output und *query-io* immer zu verwenden?

Antwort

2

Ja, Sie Code ist einfach, aber die erste ist zu klären, was Sie tun:

* Abfrage-io * ist eine globale Variable (die Sie wegen der * Namenskonvention für globale Variablen sagen kann) Das enthält den Eingangsstrom , der an das Terminal angeschlossen ist. Der Rückgabewert der prompten-Lese wird der Wert der letzten Form, zu dem Anruf Read-Line, die den String zurückgibt sie lesen (ohne die Hinter Newline.)

Dies ist, was sie sagte über * Abfrage-io *

und über die Ströme, die man dort arbeitet wie folgt setzen können:

den meisten anderen E/A-Funktionen auch T und NIL als Strom Bezeich akzeptieren aber mit einer anderen Bedeutung: als ein Strombezeichner, T bezeichnet die bidirektionalen Strom * TERMINAL-IO *, während NIL * STANDARD-OUTPUT * als Ausgangsstrom und * STANDARD-INPUT * als Eingangsstrom

in diesem Fall bezeichnet scheint es, dass dies nur zeigt auf * Standard-Eingang * und nicht zum bidirektionalen Strom t

4

Die Antwort auf eine globale Variable wie diese ist schlecht. Sie sollten nur die Antwort zurückgeben und den Anrufer tun lassen, was er damit will. Wenn Sie spezielle (~ globale) Variablen verwenden, sollten Sie Sternchen um den Namen setzen (*ANSWER* statt ANSWER).

FORCE-OUTPUT wird benötigt, um sicherzustellen, dass der Benutzer die Eingabeaufforderung tatsächlich sieht, bevor er antworten muss. Wenn ich die zweite Version mit SBCL in einem Terminal starte, friert das Programm einfach ein, um auf Eingaben zu warten, ohne etwas zu sagen.

*QUERY-IO* sollte verwendet werden, um Dinge vom Benutzer abzufragen, weil einige Umgebung möglicherweise anders als andere Ausgabe behandeln möchten. Zum Beispiel könnte jemand einen GUI-Wrapper für Ihr Programm schreiben, der die Abfragen in grafische Dialoge verwandelt. Oder sie möchten es als Teil eines Skripts ausführen und die Eingabe aus einer Zeichenfolge bereitstellen.

(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! 

bearbeiten

Ein komplexeres Beispiel SBCLs Grauströme verwenden.

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