はじめに
- 実践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*を使ってストリームを操作したほうが万能に動くということだと思う