はじめに
この連載ではCommon LispのLOOPマクロをサンプルを使って紹介する。
LOOPマクロは (cl-loopを用いることで) Emacs Lispでも利用可能である。
【Common Lisp: loopマクロ用法抄より引用】
Grahamの ANSI Common Lisp では嫌われていて碌に説明のないloopマクロ。一方、 実践Common Lisp では対照的に好んで用いられていて、全編に渡って頻繁に使われている。しかしloopマクロは難しいという意識があるのかその説明は第22章とかなり後回しにされており、ちぐはぐな感を受ける。ここでは、 黒帯のためのLOOP という題のつけられたその章で解説されているloopマクロの用法を整理してみた。
ANSI Common Lisp での黒魔術扱いに敬遠していたloopマクロだったが、こうして整理してみるとそれほど難しく考えずとも便利に使うことができそうだ。
実践Common Lisp
作者: Peter Seibel,佐野匡俊,水丸淳,園城雅之,金子祐介
出版社/メーカー: オーム社
発売日: 2008/07/26
メディア: 単行本(ソフトカバー)
LOOPのパーツ(黒帯のためのLOOPより)
LOOPの中では次のようなことができる。
- 数値的な変数や多様なデータ構造にわたる変数を更新していく
- ループしている間に見える値を収集(collect)、計数(count)、合計(sum)、最小化(minimize)、最大化(maximize)する
- 任意のLisp式を実行する
- いつループを終了するかを決定する
- それらを条件付きで実行する
上記に加えて、LOOPは以下のようなシンタックスを提供する。
- ループ内で使用するローカル変数の生成
- ループの前後に実行する任意のLisp式の指定
サンプル (GNU Emacs 28.2 で動作確認しています)
また、@javacommons さんの以下の記事内の xpand-macro/xpand を用いてマクロ展開結果を取得しています。
今回は…
今回は、「C言語やJavaScriptのfor文はどう書く?」という話題です。
教科書的には・・・
-
for ~ from ~ to ~ (by ~)
を用いるのが一般的だと思います。
(cl-loop for i from 1 to 50 by 5 collect i)
|
|
v
(let* ((i 1)
(--cl-var-- nil))
(while (<= i 50)
(setq --cl-var-- (cons i --cl-var--))
(setq i (+ i 5)))
(nreverse --cl-var--))
(1 6 11 16 21 26 31 36 41 46)
私がおススメするのは・・・
-
for i = 初期値 then (+ i 増分) while (<= i 最終値) collect/do 本体
です。
(cl-loop
for i = 1 then (+ i 5)
while (<= i 50)
collect i)
|
|
v
(let* ((i nil)
(--cl-var--_1 nil)
(--cl-var--_2 t))
(while (progn
(setq i (if --cl-var--_2 1 (+ i 5)))
(<= i 50))
(setq --cl-var--_1 (cons i --cl-var--_1))
(setq --cl-var--_2 nil))
(nreverse --cl-var--_1))
(1 6 11 16 21 26 31 36 41 46)
これなら i の増分を求める処理を複雑化したり、whileの終了条件を複雑にしたりできますね。
マクロ展開してみるとちょっと前者よりはわかりにくいですが、普通は展開なんてしませんからw
今回は、これだけ!
もっとよい書き方等ありましたらコメントで教えてください。
それでは!