今までloopマクロを怖がって避けてたけど、つかってみたら結構便利だった。

1から10までの数を集める

(require 'cl)
(loop for i from 1 to 10 collect i); =>(1 2 3 4 5 6 7 8 9 10)

collectを使うとlistに集めていくような処理になるみたい

他にもappend,nconc,sum,count,doがある

(defmacro 1from10 (action var expr)
  `(loop for ,var from 1 to 10 ,action ,expr))

(1from10 collect i (* i i)); =>(1 4 9 16 25 36 49 64 81 100)
(1from10 sum i (* i i));; =>385
(1from10 count i (oddp i)); =>5
;;appendとnconcも同じような感じ

;;あとdoは任意の式をじっこうできる
(1from10 do i (princ i))

増加する値を増やしたい時にはbyを使う

(loop for i from 0 to 100 by 10
      collect i);; =>(0 10 20 30 40 50 60 70 80 90 100)

リスト内包表記みたいにfilterを掛けながら使うこともできる

;;ifを使って
(loop for i from 0 to 10 
      if (oddp i)
      collect i); =>(1 3 5 7 9)
;;unlessもある
(loop for i from 0 to 10
      unless (zerop (mod i 3))
      collect i); =>(1 2 4 5 7 8 10)

for=で途中の値を束縛しておける

(loop for i from 1 to 3
      for sq = (* i i)
      collect sq); =>(1 4 9)

listのiteratorとして使うこともできる

;;何か要素を持ったリストを作成
(setq l (loop for i from 0 to 5
	      for sq = (* i i)
	      collect (cons i sq)))
;; =>((0 . 0) (1 . 1) (2 . 4) (3 . 9) (4 . 16) (5 . 25))
;;inを使ってリストの要素を順にたどることができる
(loop for elt in l
      if (oddp (car elt))
      collect elt); =>((1 . 1) (3 . 9) (5 . 25))

;;destructure-bindに近いこともできる
(loop for (i . sq) in l
      if (> sq 10)
      collect (list i (list sq))); =>((4 (16)) (5 (25)))

リスト操作とかをしたければこれくらい覚えれば十分な気がする。

最後に

あとは、

  • initiallyとfinallyを使って最初と最後の処理を書ける
  • whileで条件が真の間だけloopできる
  • withでloop内の変数を作成することができる。
  • returnで返す値を指定できる

ということを使えば、現在のbuffer中の"for"の数を数える処理とかが簡単に書ける

(save-excursion
  (loop initially (goto-char (point-min))
	with count = 0
	while (re-search-forward "for" nil t 1)
	do (incf count)
	finally return count)); =>19

;;他にもこんな書き方も
(save-excursion
  (loop initially (goto-char (point-min))
	while (re-search-forward "for" nil t 1)
	count t));; =>19

;;loopを使わないとこんな感じかな?
(let ((count 0))
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "for" nil t 1)
      (incf count))
  count));; =>19

あまり複雑なことをしようと思わなければloopは難しくない。
今度からもっとloopを使うようにしよう。