(defmacro for-wrong1 (var start end &rest body) (declare (indent 3)) `(let ((,var ,start)) (while (<= ,var ,end) ,@body (setq ,var (1+ ,var))))) ;; 123nil ;; でもendが関数だったら、副作用も一緒に繰り返される ;; そして評価回数は4回となる。 (for-wrong1 i 1 3 (princ i)) ; => nil ;; 333nil (for-wrong1 i 1 3 (princ 3)) ; => nil ;; 3333333nil (for-wrong1 i 1 (princ 3) (princ 3)) ; => nil ;; 3333nil (for-wrong1 i 1 (princ 3) nil) ; => nil ;; 変数捕捉の問題が残ったマクロ ;; もしマクロ定義の外でlimitが定義されていたら ;; 望まれない結果となる (defmacro for-wrong2 (var start end &rest body) (declare (indent 3)) `(let ((,var ,start) (limit ,end)) (while (<= ,var limit) ,@body (setq ,var (1+ ,var))))) ;; 結果は3nil (for-wrong2 i 1 (princ 3) nil) ; => nil ;; マクロの外で定義したlimit=7は ;; マクロの中のlimit=3に喰われた (let ((limit 7) ret) (for-wrong2 i 1 3 (setq ret limit)) ret) ; => 3 ;; とどのつまり、マクロの外で定義しえない ;; 変数を定義すればよいわけだが、 ;; ムチャクチャな名前の変数を定義するのはエレガントじゃないので ;; gensym関数を使って絶対他とはかぶらないシンボルを作成する (defmacro for (var start end &rest body) (declare (indent 3)) (let ((limit (gensym))) `(let ((,var ,start) (,limit ,end)) (while (<= ,var ,limit) ,@body (setq ,var (1+ ,var)))))) ;; でもまあloopがあるので特別ループをマクロ定義する必要はない ;; 123nil (for i 1 3 (princ i)) ; => nil ;; 333nil (for i 1 3 (princ 3)) ; => nil ;; 3333333nil (for i 1 (princ 3) (princ 3)) ; => nil ;; 3nil (for i 1 (princ 3) nil) ; => nil
P183
![Emacs Lispテクニックバイブル Emacs Lispテクニックバイブル](http://ecx.images-amazon.com/images/I/51Wg39T8KAL._SL160_.jpg)
- 作者: るびきち
- 出版社/メーカー: 技術評論社
- 発売日: 2011/11/26
- メディア: 単行本(ソフトカバー)
- 購入: 5人 クリック: 220回
- この商品を含むブログを見る