1. loopの蓄積節の-ing形の別名
Common Lisp の loop マクロには、各蓄積節に -ing 形の別名が用意されています1。
(loop for x in '(1 2 3 4 5)
collecting (* x x)) ; collect でも collecting でも動くCode language: Lisp (lisp)
collect と collecting、sum と summing、count と counting——どちらを書いても動作は完全に同じです。
なぜ2系統存在するのでしょう。
1.1. 「スタイルの多様性のため」
Common Lisp the Language 第2版、CLtL2 には、こう書かれています2。
-ingキーワードと非-ingキーワードのあいだに意味的な差はない。
ユーザーのスタイルの多様性のために提供されている。
私はloopを使うときは非-ing形を好む。
——Guy L. Steele Jr.
設計者自身は「自分は非 -ing 形を好む」と注記したうえで、両方を規格に入れています。
「好みで選べばいい」という話に見えますが、なぜそもそも両形式が存在するのかはわかりません。
1.2. loop の来歴を辿る
loop マクロの起源は MIT にあり、1980〜81 年にかけて Glenn Burke と David Moon を中心に開発されました3。loopは、MacLisp と Lisp Machine Lisp(ZetaLisp)の両方で動くように設計され、Burke 自身が書いた技術メモ TM-169「LOOP Iteration Macro」がその原典です4。
loopマクロのアイディアは、Interlisp の CLISP(Conversational Lisp)にある FOR-DO-WHILE 構文でした5。
Warren Teitelman が設計したこの構文は、ALGOL 的な英語風キーワードを Lisp に持ち込む試みでした。
ただし MIT の loop は CLISP とは非互換で、「東海岸版」として独自に発展したことになります6。
Common Lisp の標準化(1981 年〜)にあたって、Lisp Machine Lisp・MacLisp・NIL(New Implementation of Lisp)などの方言が統合されました7。
MIT の LOOP はこの時点で「MacLisp・ZetaLisp・NIL との互換を保つ」と明記されており、Common Lisp はその実装をほぼそのまま取り込みました。
つまり -ing 形と非 -ing 形は、Common Lisp が生まれる前の 1980 年代初頭からすでに ZetaLisp や NIL に存在していたのです8。
2. 既存の使用例への互換
Common Lisp コードでは、-ing 形は少数派です。
Practical Common Lisp のような教科書では -ing 形は説明の中に例示されますが、コードの主流は非 -ing 形です9。
ただ、公開されているライブラリにはいくつか実例が確認できます10。
たとえば、celtk では、スロット定義を組み立てる箇所で collecting が使われていました。
簡略化したコード片を示すと、
(loop for (slot-name nil) in tk-options
collecting `(,slot-name :initform nil
:initarg ,(intern (string slot-name) :keyword)
:accessor ,slot-name))Code language: Lisp (lisp)
また、mgl-gpr では、誤差の総和を求める処理に summing が使われていました。
(loop for x from 0d0 to 10d0 by 0.5d0
summing (let ((*x* x))
(abs (- (eval expr)
(eval target-expr)))))Code language: Lisp (lisp)
-ing 形は今も動作しますし、使用例も散見されます。
MacLisp や ZetaLisp の時代に書かれたコードとの互換として規格に組み込まれ、そのまま今に至っているというのが実態に近いでしょう。
3. 分詞構文としての語感
どちらを選ぶかに一貫したルールはなく、書いた人の癖か偶発的な選択に見えます。
ただ、-ing 形には「読み心地」の微妙な違いがあるのかもしれません。
loop は、英語風のキーワードを並べる構文で、語の並びで意味を追えるようにするCLISP の設計思想を引き継いでいます11。
loop for x in xs, sum (* x x)は、
「xs の各 x について、 x*x を合計せよ」という命令文として読めます。- 一方、
loop for x in xs, summing (* x x)は、
「xs の各 x について繰り返せ。 x*xを合計しながら」という分詞構文として読めます。
たとえば、”Walk down the street, looking for a blue door.” という英文に似た感覚で、主たる動作がloopで、summing はその反復の中で進行する付帯動作、という読み方ができるのです。
これが、”Walk down the street, and look for a blue door.”だと、少しタイミングが違います。
- あるいは
loopを名詞として見ると
「x*xを合計しているループ(loop … summing x*x)」とも読めます。
もちろん、これは標準的な英文として自然なのではなく、loop という擬似英語 DSL の内部でそう読める、ということです。
しかし、loopの「繰り返す」という処理を強調するなら、-ingの方がしっくり来ることもあるかもしれません。
- HyperSpec の構文定義では
{collect | collecting}、{sum | summing}のように両形式が等価として列挙されている。 – CLHS: Macro LOOP - CLtL2 の全文は CMU AI リポジトリで公開されており、Section 26.8 が該当箇所。 – 26.8. Value Accumulation — Common Lisp the Language, 2nd Ed.
- 論文タイトルは “LOOP Iteration Macro”(1980年)。著者は Glenn Burke と David Moon。 – LOOP Iteration Macro — Semantic Scholar
- 1986 年に Glenn Burke が Common Lisp 向けに移植した版がベースで、著作権表示は Copyright 1980, 1981 by MIT。 – MIT LOOP: The original MIT Loop macro implementation — CMU AI Repository
- CLISP は Warren Teitelman が設計した、Interlisp 上で ALGOL 風の構文を使えるようにする拡張。 – CLISP — Conversational LISP (IJCAI 1973)
- Burke と Moon の論文要旨に「LOOP was inspired by the ‘FOR’ facility of CLISP in InterLisp; however, it is not compatible and differs in several details」と明記されている。 – LOOP Iteration Macro — Semantic Scholar
- Common Lisp の標準化は 1981 年の DARPA スポンサードの会議がきっかけで、Symbolics・SPICE プロジェクト・NIL プロジェクト・S-1 Lisp プロジェクトが参加した。 – Common Lisp — Wikipedia
- Lisp Machine Manual(ZetaLisp のマニュアル)の LOOP 章は Glenn Burke による TM-169 の再録で、ZetaLisp 時代から両形式が存在していたことを示唆している。 – Lisp Machine Manual — tumbleweed.nu
- Peter Seibel の Practical Common Lisp(Chapter 22)では「Also available as synonyms are the present participle forms: collecting, appending…」と説明しつつ、コード例は非
-ing形が多い。 – 22. LOOP for Black Belts — Practical Common Lisp - celtk、McCLIM、split-sequence、mgl-gpr などの公開ライブラリで
collecting・maximizing・summingの使用例が確認できる。 – kennytilton/celtk — GitHub - CLISP の論文では「infix operators、IF-THEN statements、FOR-DO-WHILE-UNLESS-FROM-TO-etc. expressions を LISP の構造や表現を変えることなく導入する試み」と説明されている。 – CLISP — Conversational LISP (IJCAI 1973)