実践CommonLispを読むその11

第十四章 ファイルとファイルI/O

ファイルのOPENとCLOSEのお話。

  (open "/home/users/file.txt")

で簡単オープン。ファイルが存在しない場合の処理をOPEN関数に指示する事もできる。

(let ((in (open "/home/users/file.txt" :if-does-not-exist nil)))
  (when in
    (format t "~a~%" (read-line in))
    (close in)))

「if-does-not-exist」を付与する事によりファイルが存在しなかった場合の動作を変えることができる。「error」ではエラーを出力する、これでがデフォルト。「create」が存在しなければファイルを作成する。「nil」が存在しなければNILを返す。って事です。

「when」で「in」をチェックしNILなら動作しないって事だよね。

ファイルの出力に関してはこんな感じ、

  (open "/home/users/file.txt" :direction :output :if-exists :supersede)

OPEN関数のストリームの方向を変えるってことですね。デフォルトは入力なんで、入力の場合は、「:direction」は必要ないって事です。

なんかいろいろあるんですけど、OPEN関数やCLOSE関数を直接呼ぶことは少ないみたい。なぜなら〜OPEN関数でこけたとき必ずしもCLOSE関数まで処理が進むとは限らないんで、直接呼ぶ際は気をつけてねだって。ファイルストリームって有限なんでCLOSEしないといけないわけよ。OPENしたまんまだと、その内、ファイルストリームがなくなって以後ファイルがオープンできなくなる。よってOPENしたらCLOSEしましょ。

(let ((in (open "/home/users/file.txt" :if-does-not-exist nil)))
  (when in
    (format t "~a~%" (read-line in))
    (close in)))

上記の場合、OPEN関数でNILが返ってきたら処理終了。CLOSE関数が動かない、ダメですよね。だから〜安心してOPEN、及びCLOSEできるマクロを利用する。

(with-open-file (stream-var open-argument*)
  body-from*)

「with-open-file」マクロを利用するのが一般的。

まあ、あとはシステム間の汎用性を高める方法が書いてあったな、WindowsLinuxでのファイルパス指定方法の違いを書いてあった。

第十五章 実践:パスネーム可搬ライブラリ

LISP処理系に依存しないパスネームを取得するライブラリを作成しようって感じかな。

[0]> *features*
(:READLINE :REGEXP :SYSCALLS :I18N :LOOP :COMPILER :CLOS :MOP :CLISP :ANSI-CL
 :COMMON-LISP :LISP=CL :INTERPRETER :SOCKETS :GENERIC-STREAMS
 :LOGICAL-PATHNAMES :SCREEN :FFI :GETTEXT :UNICODE :BASE-CHAR=CHARACTER :PC386
 :WIN32)

「*features*」で設定されている環境変数みたいなものを表示できる。へ〜って感じ。Windows環境で動かしているからね。あとCPUも386系だよ、ふ〜ん。

LISP処理系に応じて処理を記述するには、

(defun foo()
 #+allegro (do-one-thing)
 #+sbcl (do-one-thing)
 #+clisp (do-one-thing)
 #+cmu (do-one-thing)
 #-(or allegro sbcl clisp cmu) (error "Not implemented"))

となるわけだ。「#+処理系」で、その処理系に対する処理を記述できる。便利だよね、この事によってLISPの処理系を意識したコーディングができるというわけだ。ある程度汎用的な処理を書けるんだね。という事は他の処理系の事も知らなければいけないって事だよね。無理だよ。CommonLispだけで精一杯な私にとって他の処理系まで考えてコーディングしろってのが気が早いと思う。

ので今は処理系ごとの違いを吸収しない。ちなみに上記手法の問題点は、処理系が増えたら、最後の「#-(or ... ... ...)」に追加しなければいけない。忘れそうだよね。

更にちなみに、「(do-one-thing)」の内容が同じならば、まとめることもできる

(defune foo()
 #+(or allegro sbcl cmu)
 (do-one-thing)
 #+clisp
 (do-other-thing)
 #-(or allegro sbcl clisp cmu) (error "Not implemented"))

なるほどね、面白いと思う。

・・・半分近く「実践CommonLisp」を読んできたんだけど少しは身についているかな?どうだろう、Lispって言語がどういったものか多少理解したつもりでいるんだが、やっぱりまだまだ奥深いところもあるのかな。まあいいや、今年最後の挑戦として年内に読みきるべし!