はプログラミング言語である。Common Lisp の略称はCLごくまれにclispとも。なおCLISPという実装が実在するので混同回避のためあまり用いられない。規格はANSIによる ANSI INCITS 226-1994 (S2018)。仕様を指すこともあれば、実装を指すこともある。いくつかの、自由ソフトウェアの定義に合致したライセンスによりライセンスされている実装や、オープンソースの定義に合致したライセンスによりライセンスされている実装や、プロプライエタリなライセンスによりライセンスされている実装がある。
Common Lisp には、多くの LISP 系言語に共通にみられる特徴の他に、いくつかのプログラミングパラダイムを取り込んだマルチパラダイムプログラミング言語の標準規格という面がある。
関数型だけでなく、手続き型的な言語要素に関しても標準化している。 関数単位の細かで反復的なコンパイルにより、効率的な実行を可能にすると同時にREPLによる動的で迅速な開発をサポートする。 関数オブジェクト、複素数、有理数、多倍長整数などを第一級オブジェクトとして持つ。 マルチメソッド機能をサポートした強力な動的オブジェクトシステム Common Lisp Object System を備える。 assert関数による基本的なテスト駆動開発が可能。 「例外/ハンドラ」の処理をさらに一段階分離した「Condition/Restart/Handler」による例外処理。 マクロ(プログラムによるコンパイル時のコード変換)やリーダーマクロ(特定の文字に対して新しく構文を拡張する)といった標準機能により言語を拡張可能。
構文 S式による構文である。
意味 評価順 評価順は、非常に単純な「左から右」、「内側から外側」モデルである。「左から右」を仕様として明示的に決めているという点は特徴と言えるかもしれない。他のプログラミング言語ではそうでないものも多い。
(F A1 A2) のようなS式で、Fが関数ならば、その引数 A1、A2 を左から右へ順番に評価し、最後にFにその引数を渡す。Fがマクロならば、まずマクロを展開する。
;; 2 と 2 を足す (+ 2 2) → 4
;; 与えられた数を二乗する関数を定義 (defun square (x) (* x x))
;; 関数を実行 (square 3) → 9
静的スコープ
Common Lispでは静的スコープである。Common Lisp よりも昔の多くの LISP 系言語では動的スコープであるものが多い。
データ型 Common Lispの型システムは階層的である。型は deftype を用いて定義され、一つの型にはスーパータイプ(上位型)とサブタイプ(下位型)という概念が伴う。 t がすべての型に共通のスーパータイプである。従って、全てのオブジェクトは型 t のインスタンスである。一方、型 nil は、どのオブジェクトもそのインスタンスにならない型である一方で型nullは、オブジェクトNILを表す型である。。
型には組み込み型とそうでないものがある。組み込み型は、整数、浮動小数、複素数、文字等といった基本型に、配列やストリームなど組み込み型を合わせたものである。組み込み型でない型には、構造体、クラスなどがある。このように、型システムはクラスおよびオブジェクトシステムと連続的に融合されている。
型は「型指定子」という記述方式で参照され、これはよく「タイプスペック」と呼ばれる。型指定子を用いて議論する上で、組み込み型とは直交する概念として、原子型(アトミック・タイプ)と複合型(コンパウンド・タイプ)という概念がある。複合型 は、大雑把には、引数を取ることのことができる型である。例えば、(array fixnum (5 * 7)) は、データ内容がすべて整数型で、サイズが次元ごとに「5、可変長、7」である配列を示しているこのようなtypespecは、配列の型arrayのvalid type specifierである。。
複合型では、本来の型に合わせて、特定の一変数関数を型判定に用いることもできる。例えば、型 mod3 を以下のように定義できる。
(defun mod3 (n) (= (/ n 3) 0))
(deftype mod3 () `(and fixnum (satisfies mod3)))
しかし、Common Lisp には Haskell における型変数のような概念はない。上の array の例における引数は、変数ではなく定数として処理されるためである。
アトム ATOM Common Lispにおけるアトムとは、誤解を恐れず簡単に言うと「括弧によって囲まれないもの」すべてを指す。数値はアトムである。シンボル、文字列、文字もアトムである。ANSI Common Lisp では「Compound type (not cons)」として定義されているCLHS: Type ATOM。
数値型 (NUMBER) 様々な型がある。
NUMBER COMPLEX REAL FLOAT SINGLE-FLOAT DOUBLE-FLOAT RATIONAL INTEGER SIGNED-BYTE UNSIGNED-BYTE FIXNUM BIGNUM RATIO
は数値表現に 多倍長整数 を用いて任意のサイズと精度を実現している。有理数型が分数として正確に表現されるという点は、他の言語にあまり見られない特徴である。 は自動的にそれぞれの数値型を適切に変換する。
文字 の文字型 (char) は、文字の範囲に限定されない。これは が 以前からあった事を考えれば驚くようなことではない。いくつかの最近の処理系は 文字をサポートしているCLiki : Unicode support。文字列は、下で述べるシーケンスのサブタイプである。
シンボル シンボル型はとは、ユニーク(シングルトン)で、なおかつ、いくつかの属性(スロット)を備えた名付きのデータオブジェクトである。シンボルの備える属性のなかでは値セルと関数セルが最も重要なものである(これらは「名前空間」のことである)。シンボルは、変数の値を保持するための、他の言語でいう識別子として使われる事が多いが、それ以外の用法が多数存在する。通常、シンボルを評価するとその値が返る。いくつかのシンボルは評価するとそのシンボル自身が返る。例えば、キーワードパッケージ中のシンボルはすべて自己評価シンボルである。 における真偽値は、自己評価シンボル t と nil によって表現される。 はパッケージと呼ばれるシンボルのための名前空間を備えている。
データ構造
シーケンス におけるシーケンス型は、リスト、ベクタ、ビットベクタ、文字列からなる。map や reduce などの多くの操作は、任意のシーケンス型に対して動作する。
のリストはコンス(コンスセル、ペアとも呼ばれる)で構成される。コンスセルは carとcdr の二つの属性を備えたデータ構造である。リストはコンスセルを繋ぎ合わせたものである。それぞれのコンスセルの car 属性はリストの要素(他のリストである可能性もある)を参照し、cdr 属性は次のコンスセルを参照する。ただし、最後のコンスセルの cdr だけは を参照する。コンスセルによって、簡単に木構造やその他の複雑なデータ構造を実現できるが、大抵他のデータ構造を使うか、クラスのインスタンスを使うほうが推奨される。
配列
は多次元の 配列をサポートしており、また必要に応じて配列を動的にリサイズする事も可能である。多次元配列は行列演算に利用される。ベクタは一次元の配列である。配列は任意の型を要素として持つことができる(一つの配列に複数の型の要素を混在させることもできる)が、それに加えて、整数のベクタのように要素を特定の型に特定化することも可能である。多くの実装では、型指定された配列を使う場合には、配列操作の最適化が可能である。型指定された配列のなかで二種類が標準で定義されている。文字列は文字を要素としたベクタであり、ビットのベクタはビットベクタである。
ビットベクタとベクタはシーケンスのサブタイプでもある。
その他
ハッシュテーブルはデータオブジェクト間の関連を保持する。任意のオブジェクトがキーもしくは値として使用可能である。ハッシュテーブルは配列のように必要に応じて動的にリサイズされる。パッケージはシンボルの集合であり、主にプログラムの一部を 名前空間 で分割するために使用される。パッケージはいくつかのシンボルをエクスポートすることで、インターフェースを公開する。構造体 は C言語の構造体や のレコードに似たものであり、複数の属性(スロットと呼ばれる)で構成される複合的なデータ構造である。クラスのインスタンスは構造体に似ているが、これはオブジェクトシステムによって作られるものである。
関数 では、関数 もデータ型の一つである。たとえば、これは他の関数を引数として取る関数を書く事を可能としたり、関数を返すような関数を書く事を可能とする。これにより、非常に汎用化された操作を記述できるようになる。このため、 のライブラリは、多くの部分が高階関数の上に成りたっている。たとえば、sort 関数は、引数として「比較オペレータ」を取る。これは、比較関数が任意の型のデータを整列できるだけでなく、キーによって任意のデータ構造を整列することも可能にする。
;;「 > 関数」を比較オペレータとして用い、リストを整列する (sort (list 5 2 6 3 1 4) #'>) → (6 5 4 3 2 1)
;; リスト内のサブリスト中の最初の要素 (car) に沿ってリストを整列する (sort (list '(9 a) '(3 b) '(4 c)) (lambda (x y) (< (car x) (car y)))) → ((3 b) (4 c) (9 a))
関数定義 defun マクロは関数を定義する。関数定義は名前と、引数の名前、そして関数本体で構成される。
(defun square (x) (* x x))
関数定義は、コンパイラに最適化設定や引数のデータ型を指定に関するヒントを与えるための 宣言や、 システムに対話的なドキュメンテーションを与えるためのドキュメンテーション文字列を含むことがある。
(defun square (x) "Calculates the square of the number x." (declare (number x) (optimize (speed 3) (debug 0) (safety 1))) (* x x))
無名関数は lambda 式を用いて定義される。 的なプログラミングスタイルでは、高階関数の引数として無名関数を使う場合が多い。
関数の定義や操作に関する多くのオペレータが存在する。たとえば、関数は compile によって再コンパイルされる場合がある。(いくつかの システムでは、明示的なコンパイル命令があるまで、デフォルトでは関数をインタプリタで実行するものや、オンザフライで関数を実行するたびにコンパイルするものなどがある)
総称関数とメソッドの定義 defgenericマクロは、総称関数(ジェネリック関数)を定義する。defmethodマクロはメソッドを定義する。総称関数はメソッドの集合である。メソッドはそのパラメータとして渡されたクラスやオブジェクトによって特定化される。総称関数が呼び出されると、マルチメソッドディスパッチ(多重メソッドディスパッチ)により、実際に使用されるメソッドが決定される。
(defgeneric add (a b)) (defmethod add ((a number) (b number)) (+ a b)) (defmethod add ((a string) (b string)) (concatenate 'string a b))
(add "Zippy" "Pinhead") → "ZippyPinhead"
(add 2 3) → 5
総称関数もファーストクラスのデータ型である。 総称関数やメソッドには上に記載したよりも、もっと豊富な機能が存在する。
関数名前空間 関数名のための名前空間は、データ変数のための名前空間とは分離されている。これは と対比されることの多い との主要な違いである。defun、flet そして labels のようなオペレータは関数名前空間へ名前を定義する。
他の関数への引数として関数名を渡す場合には、function スペシャルオペレータ(通常 #' と略記される)を使う必要がある。最初の sort 引数では、関数名前空間にシンボル > で定義された関数名を #'> というコードで参照している。
の評価モデルはより単純で、単一の名前空間のみが存在し、引数部分だけでなくあらゆる位置で、評価順序を問わずフォームは評価される。この事が と のどちらかの方言で書かれたコードは、ときどき他方の経験を持つプログラマーを混乱させることになる。たとえば、 プログラマーの多くは list あるいは string といった説明的な変数名を使用する事を好むが、これらの名称は ではローカルに関数名を上書きしてしまうという問題を起こすことになる。ただし、これには一長一短がある。名前空間が分かれているために、高階関数などに渡す関数の名前は、そのままではなく、関数の名前であることを明示する必要が発生してしまっている。
関数に独立した名前空間を持つ事が利点かどうかは、 コミュニティにおける論争の源となっている。この論争は一般に「 の議論」と言われる。この用語は リチャード・ガブリエル と ケント・ピットマン らによる二つの手法を広範囲にわたって比較した 1988年の論文で作られた。
その他の型 が備えている他の型は以下の通り:
パス名 は ファイルシステム におけるファイルやディレクトリを表現する。 のパス名機能は、ほとんどのオペレーティングシステムのファイル命名規則より一般的なものであり、プログラムが様々なシステムを通してポータブルにファイルにアクセスする事を可能としている。 入出力ストリームは、端末や開かれているファイルのような、バイナリデータ、テキストデータの入力元と出力先を表現する。 は組込みの 擬似乱数生成器(PRNG)を備えている。ランダムな状態オブジェクトは擬似乱数のソースとして再利用可能であり、ユーザーが乱数の種を与える事や、同じ数列を再生する事を許可している。 コンディションはエラーや例外、その他のプログラムが反応する可能性がある有意なイベントを表現するための型である。 クラスは第一級のオブジェクトである。そして、それ自身がメタクラスと呼ばれるクラスのインスタンスである。
スコープ 他のプログラミング言語におけるプログラムと同様に、 のプログラムも変数や関数、その他の要素を参照するために名前を用いる。名前が参照するものは、スコープによって決定されている。
名前と、それが参照する実体との関係を束縛(バインディング)と呼ばれている。
マクロ 系言語におけるマクロは、表面上は関数と同じように使われる。しかし、それは評価される式を表すというよりプログラムのソースコードの変形を表現している。
マクロはプログラマーに言語内に新しい構文フォームを作る事を可能とする。たとえば、下記のマクロは Perl のような言語で馴染みのある until ループのためのフォームを実現する。
(defmacro until (test &body body) `(do () (,test) ,@body))
;; 利用例 (until (= (random 10) 0) (write-line "Hello"))
;; 定義したuntilのマクロ展開 (macroexpand-1 '(until (= (random 10) 0) (write-line "Hello"))) → (DO () ((= (RANDOM 10) 0)) (WRITE-LINE "Hello")) T
すべてのマクロは、内に含むソースコードが評価、あるいはコンパイルされるよりも前に必ず展開される。マクロは抽象構文木(S 式)を受けとり、それを変更して返す関数だと考えることができる。これらの関数は、最終的なソースコードを生成するために評価器やコンパイラよりも前に呼び出される。マクロは通常の で記述され、任意の オペレータ(あるいは自作のオペレータ)を使うことができる。上の例で使用されているバッククォート記法は一般的なコードテンプレートへの代入を単純化するために によって提供されているものである。
は オブジェクト指向プログラミング のための道具として、()を備えている。これは、現在利用可能な言語の中で、もっとも強力なオブジェクトシステムの一つである。1984年当初の Common Lisp には含まれていなかったが、後に の 標準規格の一部となった。 や のような静的な言語のオブジェクト指向機能とは根本的に異なった動的オブジェクトシステムである。
他の LISP 系言語との比較 と最も頻繁に比較対照されるのが である — これら二つは最も有名な 系言語だからだ。 は よりも古く、同じ の伝統から生みだされただけでなく、同じエンジニアのガイ・スティール・ジュニア彼はジェラルド・J・サスマンとともに を設計した。が 委員会の議長を務めた。
スコープ 以前の多くのLispの方言や実装とは異なり、Common Lisp は Scheme と同様な、スコープは静的スコープのみを基本とする仕様である。Lisp Machine Lisp や MACLISP といった Common Lisp の設計に寄与した実装の多くは、インタプリタでは動的スコープを、コンパイラでは静的スコープ、という挙動になっていた。Schemeはそういったものとは異なり、静的スコープのみであった。Common Lisp は動的スコープをもサポートしているが、明示的な special 宣言が必要である。ANSI Common Lisp のインタプリタとコンパイラの間にはスコープに関しての相異点は全く存在しない。
シンボルに紐づく名前空間 時々、 は「」、 は「」と呼ばれることがある。これは が関数名と変数名(2つ)にそれぞれ独立した名前を備えている事に起因した名前である。しかし、実際には は go タグやブロック名、シンボルのプロパティなど多くの名前空間を持っている。複数の名前空間に関するトレードオフについて、 と のそれぞれを支持する論争が長いあいだ行われている。 では変数名と関数名の衝突を避ける必要があるため、 の関数はよく lis や lst、lyst といった関数名と衝突しないような引数名を取ることになる。一方 では引数として使う場合に、明示的に関数の名前空間を参照する必要がある。これは上にでてきた sort のサンプルのように一般的なことである。
真偽値リテラル はまた、真偽値の扱いが とは異なっている。 は真と偽の表現として #t と #f という特別な値を用いている。 は、より古い 系言語の伝統に従ってシンボルの t と nilnil はまた、空リストをも表現する。を使っている。 においては、if のような条件式において任意の nil でない値が真として扱われる。このことは、いくつかのオペレータが述語として働くと同時に、後の計算に使うための有意な値を返すものとして動作する事を可能としている。
末尾再帰 の標準規格は 末尾再帰の最適化 を要求しているが、 の規格はしていない。ほとんどの 実装は末尾再帰の最適化を提供するが、それでもプログラマーが最適化宣言を使った場合のみである場合が多い。それにも関わらず、一般的な のコーディングスタイルは スタイルで好まれるようなあらゆる場合に再帰を使うというやり方とは異なっている。 プログラマが末尾再帰で表現するものを、 プログラマーは do、dolist、loop等の反復構文で表現する。
実装 は、唯一の実装により規定されるものではなく、 やC言語のように仕様によって規定されている。
実装は、標準規格でカバーされていない機能を提供するライブラリとともに配布される傾向がある。そのような追加機能をポータブルに利用可能とする 自由ソフトウェア ライブラリが作成されている。最も顕著なものが、Common-Lisp.net や プロジェクトである。
の評価器は式を評価する前にコンパイルする所謂インクリメンタルなコンパイラとして実装が可能なように設計されている3.1 Evaluation。関数のインライン展開のような最適化コンパイルのための標準的な宣言も言語規格内で規定されており、多くの 実装は関数を機械語へとコンパイルする。また、性能では劣るが、バイトコードへとコンパイルする処理系も存在する。また、コンパイル済みのコードとコンパイルされていないコードを混交させても動作に差異がないように言語が設計されているためインタプリタを搭載する処理系でもコンパイラのみ搭載の処理系と動作に違いがない。
のような、 上で動くいくつかの実装は、システムが やシェルインタプリタを透過的に呼び出すのと同様に スクリプトのインタプリタ32.6. Quickstarting delivery with CLISPとして使うことができる。
処理系 再配布可能な実装の一覧
(SBCL) 後述のCMUCL から分岐して保守性を大幅に強化した処理系History and Copyright - Steel Bank Common Lispであり、現在通常のx86コンピュータで最も使用されている実装の一つ。SBCL は、REPLから入力された評価式であっても、インタプリタを介さず全てネイティブコードにコンパイルしてから実行する最近、インタプリタのサポートも試験的に実装されている。。CMUCL譲りのコンパイラにより非常に強力な最適化を行うことが出来、生成するコードはC言語のコードを上回ることもある。SBCL は、CMUCL が動作するプラットフォームに加えて、(、、)、、 上でも動作する。ただし、HP-UX 上では動作しない。 (CCL) 自由な処理系であり、SBCLと並んで使用されている実装。祖先はMacintoshをプラットフォームとするMacintosh Common Lispという商用の処理系であったが、他のOSプラットフォームへオープンソースとしてフォークされるようになり混同を避けるためClozure CLと改名したClozure CL History。その歴史のため、Mac OS の Cocoa API との連携(実装による独自機能)に強みをもつほか、ファイルの遅延ローディング、デバッグメッセージのわかりやすさなどの特色を持つ。現在は 、、(、 x86-64) に移植されているhttp://trac.clozure.com/openmcl 。 (ECL) 後述のGCLから派生した、C言語で作成されたプログラムに組み込むために設計された処理系である。lispコードはCのコードに変換された上でコンパイル実行されるので、最低限のCコンパイラしか提供されていない組み込み機器などの環境でも、クロスコンパイルにより利用することが出来る。また、C言語の高速性も受け継いでいる。 (ABCL) 仮想マシン上で動作する実装である。同マシンのJavaバイトコードへのコンパイラを備えており、 プログラムから のライブラリにアクセスする事が可能。この処理系は のコンポーネントであるが、単独で利用する事もできるhttp://armedbear.org/abcl.html 。近年もアクティブに開発されている。 (CMUCL) カーネギーメロン大学 で開発された実装を起源とする。現在はボランティアグループによりメンテナンスされる。Pythonと呼ばれる(プログラミング言語の Python とは関連なし)高速なネイティブコードコンパイラの起源となった実装である。 x86 上の や BSD、 上の 、、、HP-UX、を含むなどで動作する。
バイトコードコンパイラを備えた実装である。移植性に富み、多くの や、 などの に類似したシステム、および 、その他のオペレーティングシステムで動作する。 (GCL) から発展したGNUプロジェクトの製品である。完全な 準拠ではないが、数学ツールの や 、 などを含むいくつかの大規模なプロジェクトで採用されている。この処理系は 11 の異なるアーキテクチャ上の で動作し、 や 、 でも動作するhttps://www.gnu.org/software/gcl/ 。 (MCL) デジツール社http://www.digitool.com/ 製の処理系である。MCL 5.2 からオープンソース化された。 上の で動作する。
x86 アーキテクチャ用の処理系であり、オペレーティングシステムに依存しない。
を備えたバージョンが存在する。 は と 、 を備えており、複数の言語を混在させたプログラミングが可能である。また、全ての言語が逐次的にコンパイルされる。コンパイラと通信する に類似のエディタが統合されている。
の大半をサブセットとして実装した のライブラリであるhttps://jatha.sourceforge.net/ 。
Windows用の統合開発環境。コーマン・テクノロジーズhttp://www.cormanlisp.com/ による商用処理系だったが、2015年にオープンソース化https://github.com/sharplispers/cormanlisp
商用の実装
https://www.franz.com/ による処理系。
http://www.lispworks.com/ による処理系。
http://www.scieneer.com/ による処理系。
著名なアプリケーション 政府機関、非営利団体での利用
ハッブル宇宙望遠鏡 運用管理のためのプランニング・スケジューリングシステムhttp://www.stsci.edu/resources/software_hardware/spike/ 。 角度変更や、指定地点の撮影などのさまざまな指令を、燃料や希望時間帯など多様かつ複雑な制約のもとで、最適にスケジューリングする。 (remote intelligent self-repair software, RAX) NASA Deep Space 1 に搭載された、自己修復・監視用人工知能。NASA Ames Research Center および NASA JPLによって開発された。人間の監視なしで探索機を航行させるための自律エージェント。多数のコンポーネントからなるが、その主要な3つは、EUROPA(マーズ・エクスプロレーション・ローバー のためのプランニングシステム)、EXEC(プラン実行システム)、Livingstone(モデルベース異常診断システム)である。1999年度の ソフトウェア・オブ・ジ・イアー賞を受賞したhttp://ic.arc.nasa.gov/projects/remote-agent/ 。
商用 Yahoo! ストア