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-14


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

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

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

繰り返し系(do系)のユーティリティ編です。

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

http://lib.store.yahoo.net/lib/paulgraham/utx.lisp

お題

do-all

暗記で再現

(defmacro do-all (var x &body body)
  (with-gensyms (g)
    `(let ((,g ,x))
       (if (consp ,g)
	   (dolist (,var ,g) ,@body)
	   (let ((,var ,g)) ,@body)))))
;; 動作
(do-all i '(a b c d e)
  (print i))
=>
a
b
c
d
e

(do-all i 'a
  (print i))
a

とりあえずできた。

ポイントとしては当たり前のことなのかもしれないけれど、前回のエントリでも考えていた展開時の動作について

この例では、consかどうかの判定は展開時ではなくて、実行時にされる。

自分は、極端に書けば、

(defmacro do-all (var x &body body)
  (with-gensyms (g)
    (if (consp (cadr x))
	`(let ((,g ,x))
	   (dolist (,var ,g) ,@body))
	`(let ((,g ,x))
	  (let ((,var ,g)) ,@body)))))

のようなもの(展開時にconsかを判定したりする)を書いてしまいがちなので気を付けたい。

お題

dolists

暗記で再現

(defmacro dolists (pairs &body body)
  (with-gensyms (f)
    (let ((parms (mapcar (lambda (x) (declare (ignore x))
				 (gensym)) 
			 pairs)))
      `(labels ((,f ,parms
		  (when (or ,@parms)
		    (let ,(mapcar (lambda (p g)
				    (list (car p) `(car ,g)))
				  pairs
				  parms)
		      ,@body
		      (,f ,@(mapcar (lambda (p) `(cdr ,p)) parms))))))
	 (,f ,@(mapcar #'cadr pairs))))))

とりあえずできた。

(mapcar (lambda (x)
	  (declare (ignore x))
	  (gensym)) 
	pairs)

は引数の個数だけgensymを作るという常套句らしい。(declare (ignore x))しないと警告がでるので宣言を追加した。

;; 動作
(dolists ((i '(1 2 3))
	   (j '(a b c d)))
  (print (list i j)))

(1 A) 
(2 B) 
(3 C) 
(NIL D) 

map系のように一番短いものに合わせるのではなく一番長いものに合わせたくなったときには便利な気がする。

お題

do3

暗記で再現

(defmacro do3 (v1 v2 v3 list &body body)
  (with-gensyms (g h)
    `(let ((,g ,list))
       (do ((,h ,g (cdr ,h)))
	   ((endp ,h) nil)
	 (let ((,v1 (car ,h))
	       (,v2 (if (cdr ,h)
		       (cadr ,h)
		       (car ,g)))
	       (,v3 (if (cddr ,h)
			(third ,h)
			(if (cdr ,h)
			    (car ,g)
			    (cadr ,g)))))
	   ,@body)))))
;;動作
(do3 hee foo mee '(1 2 3 4 5 6 7 8 9 10 11 12)
  (print (list hee foo mee)))
=>
(1 2 3) 
(2 3 4) 
(3 4 5) 
(4 5 6) 
(5 6 7) 
(6 7 8) 
(7 8 9) 
(8 9 10) 
(9 10 11) 
(10 11 12) 
(11 12 1) 
(12 1 2) 

とりあえずできた。

どういうときに使うのか、ぱっとは思い付かないけど、便利そうではある。

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20071014