loopマクロ
Common Lispのloopマクロは大変気持ち悪いので好きになりそうです。
一度じゃ覚えられないだろうからメモ。
;; collectは結果をリストにして返す CL-USER > (loop for x in '(0 1 2 3 4 5) collect (expt 2 x)) (1 2 4 8 16 32) ;; onだとcdrを繰り返す CL-USER > (loop for x on '(one two three) do (print x)) (ONE TWO THREE) (TWO THREE) (THREE) NIL ;; Pythonでいうrange関数の代わりに使える! CL-USER > (loop for x from 1 to 10 collect x) (1 2 3 4 5 6 7 8 9 10) ;; 10は含まない CL-USER > (loop for x from 1 below 10 collect x) (1 2 3 4 5 6 7 8 9) CL-USER > (loop for x from 10 downto 1 collect x) (10 9 8 7 6 5 4 3 2 1) CL-USER > (loop for x from 10 above 1 collect x) (10 9 8 7 6 5 4 3 2) ;; byで2を指定してみると CL-USER > (loop for x from 0 to 10 by 2 collect x) (0 2 4 6 8 10)
;; withで一時的な変数を用意できる。 ;; "collect"が"collecting"になっても動作は同じらしい。。 CL-USER > (loop with temp = (loop for x from 0 to 10 collect x) for x in temp collecting (expt 2 x) ) (1 2 4 8 16 32 64 128 256 512 1024) ;; appendの例。 appendingも↑と同様。 CL-USER > (loop for x on '(* * *) appending (list x)) ((* * *) (* *) (*)) ;; これら(do, collect, append)のほかに, ;; nconc, sum, maximize, minimize があるらしい
;; acrossでvector(一次元配列)を扱える CL-USER > (loop for x across (vector 'one 'two 'three) do (print x)) ONE TWO THREE NIL ;; ハッシュテーブルを扱う(記述が結構めんどい。。) CL-USER > (setq ht (make-hash-table)) #<EQL Hash Table{0} 216D82DB> CL-USER > (setf (gethash 'one ht) 1) 1 CL-USER > (setf (gethash 'two ht) 2) 2 CL-USER > (loop for key being the hash-key in ht collect key) (ONE TWO) CL-USER > (loop for value being the hash-value in ht collect value) (1 2) ;; usingでvalueも扱う CL-USER > (loop for key being the hash-key in ht using (hash-value value) collect (cons key value) ) ((ONE . 1) (TWO . 2))
CL-USER > (loop for x from 1 to 10 when (evenp x) collect x ) (2 4 6 8 10) CL-USER > (loop for x from 1 to 50 while (<= x 10) count x ) 10 CL-USER > (loop for x from 1 to 50 until (= x 11) collect x ) (1 2 3 4 5 6 7 8 9 10) ;; elseは省略可 CL-USER > (loop for x from 1 to 10 if (evenp x) collect x else collect (* x 10) ) (10 2 30 4 50 6 70 8 90 10) ;; returnで脱出 CL-USER > (loop with acc = nil for x from 1 to 10 do (if (= x 5) (return acc) (push x acc)) ) (4 3 2 1)
;; repeatによる繰り返しと,変数の値の更新 CL-USER > (loop repeat 5 for i = 0 then (+ i 1) do (print i) ) 0 1 2 3 4 NIL
;; 複数のケース。 平行して動作するらしい。 ;; 長さがバラバラの場合は一番短いものに合わせる。 CL-USER > (loop for a in '(h l o d) for b in '(e o r !) for c in '(l w l !) append (list a b c) ) (H E L L O W O R L D ! !) ;; これ表示するためにちょっとがんばった!!
まだ色々な姿があるようだけど,これぐらいで・・・。。
loopマクロ実装するの凄いめんどくさそう。
追記 08/07/07
ちょっとメモ
(setq ht (make-hash-table)) (setq foo '(one two three four five)) (loop for n in foo for i = 1 then (1+ i);;repeat以外でも使えるみたい! do (setf (gethash n ht) i) ) (loop for k being the hash-keys in ht2 using (hash-value v) collect (cons k v) ) ;; ((FIVE . 5) (ONE . 1) (FOUR . 4) (THREE . 3) (TWO . 2))
あと、withで用意した一時変数はincf等で値を変えられない?っぽい。
>(loop repeat 5 with i = 1 do (prog (setq i (1+ i)) (print i)) ) NIL NIL NIL NIL NIL NIL
09/01/23 訂正
ご指摘いただきました。progの使い方を間違っていました。
prog使ったことが無かったのですがprognと同じだろうと勘違いして変なことしちゃった。
;; let 同様、progの第一引数は変数の宣言 CL-USER> (prog ((x 1) (y 2) z) (print x) (print y) (print z)) ;; 本題 CL-USER> (loop repeat 5 with i = 0 do (prog () (incf i) (princ i) )) 12345 ; できた! NIL
ご指摘どうもありがとうございました。