はじめに

  • 実践CommonLispを読んでいていて、???となったところをアウトプットしてみる
  • 頑張って英語ドキュメントでも読めるようになりたい
  • (処理系はSBCLで書いています)

問題のコード(関数)

(defun prompt-read (prompt)
    (format *query-io* "~a: " prompt)
    (force-output *query-io*)
    (read-line *query-io*))
  • 実践CommonLispを読んだことがある人なら見覚えがあるかもしれない
  • この関数の使い方
(prompt-read "何か入力してください")
> 何か入力してください: hello, world!

"hello, world!"
NIL
  • prompt-read関数の引数の文言が出力される
  • ユーザーが入力した文字列を読み込む

*query-io*

  • このグローバル変数は端末に接続した入力ストリームを保持している
  • ここで定義したグローバル変数ではなく処理系の方で定義されている変数

端末に接続した入力ストリーム??

  • 端末に入力された入力値はこの*query-io*変数に保持されていく
; 例
(read-line *query-io*)
> こんにちは!

"こんにちは!"
NIL
  • こんにちは! -> *query-io* -> read-lineで読み込み
  • read-lineはデフォルトではstandard inputが指定されているらしい
  • *query-io*もデフォルトでは端末が指定されているので、
; これらはだいたい同じものと思われる
(read-line)
(read-line *standard-input*)
(read-line *query-io*)

format

  • 書籍では最初からしょっちゅう使われる関数
  • ここで突然*query-io*が引数に指定されてたもんだから困惑
; フォーマットして出力
(format t "hello, world")
hello
NIL
  • format関数は引数の文字列をフォーマットする関数
  • 第1引数のt*standard-outputと同じ
  • 第1引数指定のストリームにフォーマット結果を出力している
  • *standartd-output*に渡されると出力ストリームなので画面に表示される
(format *query-io* "hello")
  • *query-io*は入力ストリームなので、フォーマット結果は入力ストリームにわたされる
  • 画面には表示されないよ(゜∀。)!

force-output

  • これ調べたけどよくわかんなかった
  • 実際に動かしてみた挙動としては、ストリームを出力する感じ?

コメント欄にて教えていただいので反映させていただきます
* 待機状態のバッファーを強制的に出力する
* バッファを空にする処理を開始したさい、完了や確認の応答が帰ってくるのを待つことはない
* つまるところ、出力とは非同期に関数を返す
* 処理の長い出力があった際には、出力の完了を待たずに関数を返すということ
* finish-outputの方は同期的にバッファを空にするようです

(format *query-io* "~a: " prompt)
(force-output *query-io*)
  • formatでフォーマットした文字列は*query-io*に出力されるが、改行コードを含んでいないためバッファは待機状態のまま
  • force-output関数で強制的にバッファを空にする(出力する)
  • またひとつ学んでしまった

まとめ

(defun prompt-read (prompt)
    ; prompt文字列を prompt: の形式にフォーマットして入力ストリームに渡している
    (format *query-io* "~a: " prompt)
    ; 待機状態のバッファを出力
    (force-output *query-io*)
    ; 新たな入力ストリームを読み込む!
    (read-line *query-io*))
  • ちなみに。。。
(defun prompt-read2 (prompt)
    (format t "~a: " prompt)
    (read-line))
  • sbclやCLISPであれば上記でもいけた
  • ただ、書籍には「画面出力を保証する」ためにforce-output関数を使っているとあったので、他の処理系では動かないケースがあるのだと思う
  • *query-io*を使ってストリームを操作したほうが万能に動くということだと思う