with-open-fileの中で中断

無限ループさせてREPLから中断することを前提としているプログラムを書いているときに、ループの中での出力をどうやってファイルに記録するかという問題が出てくる。素直に考えると

(defun write-test ()
  (with-open-file (f "/home/masatoi/hoge" :direction :output :if-exists :supersede)
    (unwind-protect
	 (nlet itr ((i 0))
	   (format f "~A " i)
	   (sleep 1)
	   (itr (1+ i)))
      (finish-output f))))

のようになるが、この関数を実行してループ中にC-cで中断するとファイルが残らない。with-open-fileのHyperSpecを読むと、with-open-fileの中でインタラプトが入るとcloseは保証されるけど出力ファイルはなかったことにされると書いてある。
これでは困るのでopenとcloseを明示的に書いてやる必要があり、こうなる。

(defun write-test2 ()
  (let ((f (open "/home/masatoi/hoge" :direction :output :if-exists :supersede)))
    (unwind-protect
	 (nlet itr ((i 0))
	   (format f "~A " i)
	   (sleep 1)
	   (itr (1+ i)))
      (finish-output f)
      (close f))))

unwind-protectのclean-upのところにストリームのバッファの出力とcloseをやると書いておけばwith-open-fileと同じようにストリームを閉じるところまで保証されるのでファイルディスクリプタを浪費し続けることは避けられる。と思う。