Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2007-10-20


Paul Graham氏のユーティリティ その7

| 02:53 | Paul Graham氏のユーティリティ その7 - わだばLisperになる を含むブックマーク はてなブックマーク - Paul Graham氏のユーティリティ その7 - わだばLisperになる

PG氏のユーティリティを読んでみることの7回目。

今回も引き続きファイルの読み書きユーティリティ編です。

Lisp utilities that were not included in On Lisp or ANSI Common Lisp

お題

do-lines

暗記で再現

(defmacro do-lines (var path &body body)
  (with-gensyms (str p)
    `(let ((,p (probe-file ,path)))
       (when ,p
	 (with-infile ,str ,p
	   (do ((,var (read-line ,str nil :eof) (read-line ,str nil :eof)))
	       ((eql ,var :eof))
	     ,@body))))))

できた。これの場合は、内部でitが参照まずいので、awhenは使われていない様子。

行毎に何かの処理をさせるためのものの様子。

お題

file-lines

暗記で再現

(defun file-lines (path)
  (let ((i 0))
    (do-lines line path
      (setq i (1+ i)))
    i))

とりあえずできたけれど、内部の変数名は、iじゃなくてオリジナルの様にcountの方が分かりやすさの点で好ましい。

動作テスト時にどうも無限ループになってしまうので、上のdo-linesのループ終了の判定を:eofにしたらすんなり動いた。eofを定数にするってのは、なかなか扱いが難しい気がするがどうなのだろう。

お題

暗記で再現:もうちょっと

(defmacro with-outfile (str fname &body body)
  (with-gensyms (f)
    `(let ((,f ,fname))
       (in-case-error 
	(with-open-file (,str ,f 
			      :direction :output
			      :if-exists :supersede)
	  ,@body)
	(format *error-output* "Error to writing ~S." ,f)))))

再現性が今一歩足りなかった。変数名が違ったのと、エラーのところで改行忘れた。

これもまた、with-infileと同様に余分なgensymがあるのが謎。

;; 動作
(with-outfile str "/tmp/foo.txt"
  (print "foooooooo" str))
;=>"foooooooo"という内容の/tmp/foo.txtというファイルができる。

お題

暗記で再現:失敗

(defmacro with-outfiles (pairs &body body)
  (if (null pairs)
      `(progn ,@body)
      `(with-outfile ,(car pairs) ,(cadr pairs)
	 (with-outfiles ,(cddr pairs)
	   ,@body))))

引数が奇数のときのエラー処理の判定を抜かしてしまった。

正解は、

(defmacro with-outfiles (pairs &body body)
  (if (null pairs)
      `(progn ,@body)
      (if (oddp (length pairs))
	  (error "Odd length arg to with-outfiles.")
	  `(with-outfile ,(car pairs) ,(cadr pairs)
	     (with-outfiles ,(cddr pairs)
	       ,@body)))))
;; 動作
(with-outfiles (foo "/tmp/foo.txt" bar "/tmp/bar.txt" baz "/tmp/baz.txt")
  (print "foo?" foo)
  (print "bar?" bar)
  (print "baz?" baz))
;=>それぞれ指定したファイルに指定した内容が書き込まれる。

お題

copy-file

暗記で再現:もうちょっと

(defun copy-file (from to)
  (with-open-file (in from :direction :input
		           :element-type 'unsigned-byte)
    (in-case-error 
     (with-open-file (out to :direction :output 
			     :element-type 'unsigned-byte)
       (do ((b (read-byte in nil -1)
	       (read-byte in nil -1)))
	   ((minusp b))
	   ;     ここに(declare (fixnum b)) が入る
	 (write-byte b out)))
     (format *error-output* "Error writing to ~S.~%" to))))

declareを抜かしてしまった。

これは、その名の通りファイルをコピーするユーティリティの様子。コピー先に同名ファイルが存在した場合は、エラーになる。