Common Lisp の loop に
-ing 形がある理由を考える

  • Common Lisp の loop マクロには collectcollecting のように -ing 形と非 -ing 形の両方が存在し、動作は完全に同じです。
  • 両形式は Common Lisp が生まれる前の 1980 年代初頭に ZetaLisp や MacLisp にすでに存在しており、Common Lisp はそれをそのまま取り込みました。
  • -ing 形には英語の分詞構文に近い語感があり、繰り返しの中で進行する付帯動作として読める点で、非 -ing 形とは微妙に読み心地が異なります。

関連記事

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)

collectcollectingsumsummingcountcounting——どちらを書いても動作は完全に同じです。
なぜ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の方がしっくり来ることもあるかもしれません。

  1. HyperSpec の構文定義では {collect | collecting}{sum | summing} のように両形式が等価として列挙されている。 – CLHS: Macro LOOP
  2. CLtL2 の全文は CMU AI リポジトリで公開されており、Section 26.8 が該当箇所。 – 26.8. Value Accumulation — Common Lisp the Language, 2nd Ed.
  3. 論文タイトルは “LOOP Iteration Macro”(1980年)。著者は Glenn Burke と David Moon。 – LOOP Iteration Macro — Semantic Scholar
  4. 1986 年に Glenn Burke が Common Lisp 向けに移植した版がベースで、著作権表示は Copyright 1980, 1981 by MIT。 – MIT LOOP: The original MIT Loop macro implementation — CMU AI Repository
  5. CLISP は Warren Teitelman が設計した、Interlisp 上で ALGOL 風の構文を使えるようにする拡張。 – CLISP — Conversational LISP (IJCAI 1973)
  6. 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
  7. Common Lisp の標準化は 1981 年の DARPA スポンサードの会議がきっかけで、Symbolics・SPICE プロジェクト・NIL プロジェクト・S-1 Lisp プロジェクトが参加した。 – Common Lisp — Wikipedia
  8. Lisp Machine Manual(ZetaLisp のマニュアル)の LOOP 章は Glenn Burke による TM-169 の再録で、ZetaLisp 時代から両形式が存在していたことを示唆している。 – Lisp Machine Manual — tumbleweed.nu
  9. 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
  10. celtk、McCLIM、split-sequence、mgl-gpr などの公開ライブラリで collectingmaximizingsumming の使用例が確認できる。 – kennytilton/celtk — GitHub
  11. CLISP の論文では「infix operators、IF-THEN statements、FOR-DO-WHILE-UNLESS-FROM-TO-etc. expressions を LISP の構造や表現を変えることなく導入する試み」と説明されている。 – CLISP — Conversational LISP (IJCAI 1973)