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 |

2008-01-05

FORMATは深すぎる

| 18:09 | FORMATは深すぎる - わだばLisperになる を含むブックマーク はてなブックマーク - FORMATは深すぎる - わだばLisperになる

一体どんな機能があるのか極一部しか把握できていないFORMATなのですが、今日ふとFORMATTER関数ってどういう時に使うと効果的なのかな、と思い、CLtL2のFORMATTERのところを読んでみてました。

それで、FORMATは、フォーマット指定文字列だけでなく、関数も引数として取れるということを初めて知ったのですが、FORMATTERというのは、フォーマット指示文字列に従って引数を解釈して文字列を出力する関数とのこと。

うーん、そうだったのか!、と思い色々実験。

(format t (lambda (stream &rest args)
	    (do ((cnt 0 (1+ cnt))
		 (a args (cdr a)))
		((endp a))
	      (format stream "Arg:~D => ~A~%" cnt (car a)))
	    args) 
	'foo 'bar 'baz)
;=>
;Arg:0 => FOO
;Arg:1 => BAR
;Arg:2 => BAZ

定義する関数は、2引数の関数で、streamと残りの引数、といった構成。つまりformatが取る引数と同じ構成にする模様。

うーん、これだ!という便利そうな良い例が思い付かないけれど、なんだか凄そうだー。

(defun type-of-printer (stream &rest args)
  (dolist (item args)
    (format stream "Arg:~A Type => ~A~%" item (type-of item)))
  args)

(format t #'type-of-printer 'foo '(foo bar baz) 1 2 3 4)
;=>
;Arg:FOO Type => SYMBOL
;Arg:(FOO BAR BAZ) Type => CONS
;Arg:1 Type => BIT
;Arg:2 Type => (INTEGER 0 1152921504606846975)
;Arg:3 Type => (INTEGER 0 1152921504606846975)
;Arg:4 Type => (INTEGER 0 1152921504606846975)

(funcall (formatter "Hello, ~{~A ~^~}!~%") t '(foo bar baz))
;=>
;Hello, FOO BAR BAZ !

(let ((print-items-in-list (formatter "~{~A~%~}") ) )
  (funcall #'print-items-in-list t '(foo bar baz)))
;=>
;FOO
;BAR
;BAZ

(mapc (formatter "~A~%") '(t t t) '(foo bar baz))
;=>
;FOO
;BAR
;BAZ

(format t #'format #'format #'format "Hello, ~@(~A~)" 'world!)
;=>
;Hello, World!

こうやってみてみると、FORMATっていうのは、外枠だけ提供してるようなもので、どっちかというとFORMATTERが頑張っている構成になっているように見える。