2
votes

I'm reading the book Practical Common Lisp and there is a piece of code, and I'm using the Clozure CL implementation:

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

After I successfully defined the function, I called it by

(prompt-read "Hello")

And then input "hello" and pressed the enter key, the output is like:

CL-USER> (prompt-read "Hello")
Hello:hello

"hello"
NIL

an additional blank line is added, I tried the code below and there is no additional newline:

(defun test-read ()
 (read-line *query-io*))

And then executed it, the result is like:

CL-USER> (test-read)
hello
"hello"
NIL

This time no additional blank line is produced, actually I find that every time read-line follows a format function, a blank line is produced. I tried the code in Clisp implementation and neither case produces a blank line, I just want to know why the blank line appears, and another question is does read-line return two values? Because I see a NIL following the string I input every time, what does this NIL mean?

Thanks for any help!

2
Read the documentation. The second value is whether the input was terminated by EOF rather than a newline.Barmar
I suspect the blank line is being added by the read-eval-print loop, not by read-line.Barmar
@Barmar thanks for your answer, the blank line do seem to be added by the read-eval-print loop, and is dependent on the implementationHantang Liu

2 Answers

4
votes

That's an interaction of Clozure CL with the SLIME read-eval-print-loop (REPL). The native Clozure CL REPL doesn't do that.

; SLIME 2014-05-16
CL-USER> (defun prompt-read (prompt)
           (format *query-io* "~a:" prompt)
           (force-output *query-io*)
           (read-line *query-io*))
PROMPT-READ
CL-USER> (prompt-read "Hello")
Hello:hello

"hello"
NIL

If you call it multiple times, then you see that your code does not add a newline, but the REPL prints a line when some output was done, between the output and the values returned.

CL-USER> (progn (prompt-read "Hello")
                (prompt-read "Hello")
                (prompt-read "Hello"))
Hello:hello
Hello:hello
Hello:hello

"hello"
NIL

Each Lisp implementation has some special code for the SLIME backend. Maybe there is a difference.

1
votes

The blank line might come from FRESH-LINE

I don't get the output that you describe when I try similar code in SBCL (see appendix). You didn't mention what implementaiton you're using, but I expect that the REPL is outputting a fresh line, either directly with the fresh-line function, or using the tilde-ampersand format directive. Note what the documentation says about fresh-line (emphasis added):

fresh-line is similar to terpri but outputs a newline only if the output-stream is not already at the start of a line. If for some reason this cannot be determined, then a newline is output anyway. fresh-line returns true if it outputs a newline; otherwise it returns false.

It wouldn't surprise me at all if the the prompt that you displayed with (format *query-io* …) puts the system in a state where "this cannot be determined," and as a result you get the "extra" newline that you're seeing. If you change your format directive to something like "~a:~%", do you get the same behavior?

The NIL

and another question is does read-line return two values? Because I see a NIL following the string I input every time, what does this NIL mean?

As Barmar pointed out in the comments, the documentation clearly states that read-line returns two values, the second of which indicates whether the input was terminated by a newline or an end-of-file.

read-line &optional input-stream eof-error-p eof-value recursive-p
⇒ line, missing-newline-p

… The secondary value, missing-newline-p, is a generalized boolean that is false if the line was terminated by a newline, or true if the line was terminated by the end of file for input-stream (or if the line is the eof-value).

Appendix: SBCL Transcript

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

PROMPT-READ
* (prompt-read "Hello")
Hello:hello

"hello"
NIL
* (defun test-read ()
    (read-line *query-io*))

TEST-READ
* (test-read)
hello

"hello"
NIL