Common Lispについて詳しく解説

導入

Common Lisp は、Lisp ファミリーの不純な関数型言語です。

 Common Lispについて詳しく解説

導入

Common Lisp は、ANSI X3.226-1994 によって標準化された Lisp の方言です。それ以前のLispの多様なバリアントを標準化するために開発されたもので、実装ではなく、Lisp実装が準拠しようとする仕様です。 CLと略されることがよくあります。

Common Lisp汎用 プログラミング言語であり、特定の製品に組み込まれた拡張言語である Emacs Lisp やAutoLispのような Lisp の方言とは異なります。多くの古い Lisp とは異なり、 Schemeと同様に、Common Lisp はデフォルトで変数に字句スコープを使用します。

Common Lisp は、次のようなマルチパラダイムプログラミング言語です。

  • 命令型関数型オブジェクト指向プログラミング (CLOS) 手法を受け入れます。
  • 動的に型指定されますが、効率と安全性を向上させるオプションの型宣言を使用します。
  • Condition Systemと呼ばれる強力な例外管理システムを備えています。
  • マクロや再生マクロなどの機能を通じて構文的に拡張可能です。

データ型

Common Lisp には、他のどの言語よりも豊富なデータ型があります。

スカラー型

 Common Lispについて詳しく解説

数字

数値型には、整数、有理数、浮動小数点数、複素数が含まれます。 Common Lisp は、任意のサイズと精度の数値を表すために大きな数値を使用します。有理型は分数を正確に表します。 Common Lisp は、これらの型の間で数値を適切に自動的に変換します。以下は数値タワー、つまり Common Lisp の数値型の階層です。

 複素比 fixnum / / / 数値 <--+-real--+-rational--+-integer--+-bignum \ \ \ (1) signed-byte--unsigned-byte--bit \ float--+ -short-float \-single-float \-double-float \-long-float

(1) 整数と符号付きバイトは互いに素な型指定です。ただし、ドメインは同一です。

たとえば、次のような式が挙げられます。

 ( + ( sqrt - 2 ) ( / 64 ) )

返品

 #C(3/2 1.4142135)

つまり、虚数部が浮動小数点 1.4142135 であり、実数部が有理数 3/2 である複素数です。

キャラクター

Common Lisp の文字タイプは ASCII 文字に限定されません。 Lisp は ASCII よりも古いため、これは驚くべきことではありません。一部の最新の実装ではUnicode文字がサポートされています。 [1]

記号

シンボル型は Lisp 言語に共通ですが、Lisp 言語以外ではほとんど知られていません。シンボルは、名前空間に関連する一意の名前付きオブジェクトです。 Lisp のリテラルシンボルは変数識別子として使用されます。ただし、これらはより一般的であり、オブジェクトのように単独で使用することもできます。シンボルが評価されると、その値が変数として返されます。

データ型としてシンボルが存在することにより、マクロ (コンパイル時にコード変換を実行する) を作成したり、シンボリック計算システムを実装したりすることが容易になります。実際、Lisp はコンピューター代数システムを実装した最初の言語です。非常に完全なコンピューター代数システムは Lisp (Maxima と Axiom、記号変換に関しては、一般的に人気のある Mathematica や Maple と比べても遜色ありません) で書かれています。

特殊な場合があります:

  • ブール値は予約記号 T と NIL で表されます。
  • キーワード(:foo または :bar の形式) は、 KEYWORD名前空間で定義されたシンボルです。このようなシンボルを評価すると、シンボル自体が返されます。

例:

 ふー;; -> FOO 変数には値がありません。 (関数foo ) ;; → FOO関数が定義されていません。

QUOTE演算子は、シンボルを評価から保護します (シンボル自体を使用する場合)。

 ( foo を引用) ;; -> FOO 'フー;; ->FOO

シンボルが値または関数にリンクされているかどうかを尋ねることができます。

 ( boundp 'foo ) ;; -> NIL (境界値なし) ( fboundp 'foo ) ;; -> NIL (FOO という名前の関数は存在しません)

シンボルと値の関連付け:

 ( defparameter foo 77 ) ;; -> ふーふー;; -> 77

シンボルと機能の関連付け:

 ( defun foo ( bar ) ( 1 + bar ) ) ;; ->FOO

値 FOO を使用して FOO 関数を呼び出します (シンボルに値と関数用に別個のスロットがあることを示します)。

 (ふーふー) ;; -> 78 ( boundp 'foo ) ;; -> T ( fboundp 'foo ) ;; -> T (関数foo ) ;; -> # 

再帰:

 ( defun階乗( n ) ( if ( = n 0 ) 1 ( *n (階乗( -n 1 ) ) )) ) )

他の :

 (最初 ' ( 7 3 10 ) ) ;;-> 7 (残り ' ( 20 2 45 ) ) ;;-> (2 45) (終了 ' ( ) ) ;;-> T (終了 ' ( 5 ) ) ; ;-> NILでないリスト

データ構造

シーケンス

シーケンスは、要素の順序付けられたコレクションを表す抽象型です。シーケンスから派生した具象型は、リストとベクトル (ビット ベクトルと文字列を含む) です。シーケンスには多くの関数が使用できます。ただし、プログラマが独自のシーケンス サブタイプを定義することはできません。新しいシーケンスの定義を可能にする標準の拡張が現在提案されています (2007 年頃)。

ペア、リスト

Common Lispリストはデータ型ではありませんが、 cons (複数形) で構成されており、 cons またはcellと呼ばれることあります。 cons は、型 T の 2 つの要素を持つ構造体で、関数carcdr (またはfirstrest ) によってアクセスできます。したがって、リストはリンクされた con のチェーンであり、各 con の cdr は次の要素を指し、最後の cdr は NIL 値を指します。 Conses は、ツリーや複雑なデータ構造を実装するために簡単に使用できます。ただし、後者の場合は、構造体またはクラスを使用することをお勧めします。

ツリー(1 (2/7 3.14) A “foo”) は、次の CONS 文字列で表されます。

さまざまな方法で構築できますが、ここでは 2 つの方法を挙げます。

 ( list 1 ( list 2 / 7 3.14 ) 'a "foo" ) ( cons 1 ( cons ( cons 2/7 ( cons 3 . 14 NIL ) ) ( cons 'a ( cons "foo " NIL ) ) )

ペアから作成されたリストまたは循環構造はリテラル表現を持ちませんが、出力することができます。

 ( setf *print-circle* t ) ;循環構造の表示を有効にします (無限ループを回避します) ( let ( ( list ( copy- list ' ( abc ) ) )) ) ( setf ( cdr ( last list ) ) list ) ) ; => #1=(ABC . #1#)

絵画

Common Lisp は任意の次元の配列をサポートしており、配列のサイズを動的に変更することもできます。多次元配列は行列計算に使用できます。 1次元配列 (ベクトルと呼ばれる) のみがシーケンスのサブタイプです。

配列は、含まれる要素のタイプによって特殊化できます。特に、ビット ベクトルと文字ベクトル (文字列) は、言語によって標準として提供されます。

ベクター作成の例:

 ( setq v ( make- array 3 ) ) ;ベクトルの作成( setf ( aref v 0 ) 1 ) ; v[0]:= 1 ( aref v 0 ) ; -> 1

3 次元配列(4 x 2 x 3) を作成して初期化する例:

 ( make- array ' ( 4 2 3 ) :初期内容' ( ( ( abc ) ( 1 2 3 ) )) ( ( def ) ( 3 1 2 ) ) ( ( ghi ) ( 2 3 1 ) ) ( ( jk l ) ) ( 0 0 0 ) ) )

…これは以下を返します:

 #3A(((ABC) (1 2 3)) ((DEF) (3 1 2)) ((GHI) (2 3 1)) ((JKL) (0 0 0)))

記録

例:

 (本の著者のタイトルを解除) ; 3 つのフィールドを含む「book」構造を構築します( make book ) メモリ内に構造を構築します( setq l ( make-book : author 'Hugo ) ) ;著者が Hugo である本を作成し、それを変数 l ( setf ( title book l ) 'Miserables )に関連付けます。タイトルをヒューゴの本に関連付けます( title book l ) ;;-> Miserables
 Common Lispについて詳しく解説

ハッシュテーブル

ハッシュ テーブルには、オブジェクト間の関連付けが保存されます。任意のタイプのオブジェクトをキーまたは値として使用できます。ハッシュ テーブルは、配列と同様、必要に応じて自動的にサイズ変更されます。

パッケージ

パッケージはシンボルのコレクションであり、主にプログラムを名前空間に分割するために使用されます。パッケージは特定のシンボルをエクスポートし、それらをパブリックインターフェイスの一部としてマークできます。古典的なオブジェクト言語のいわゆるプライベート変数とメソッド (カプセル化の原理) は、エクスポートせずに名前空間で宣言することによって Lisp で取得されます。

構造物

構造体は、C の構造体や Pascal レコードと同様に、任意のおよび任意のタイプのフィールド (スロットと呼ばれる) を備えた、任意の複雑さのデータ構造を表します。構造体は、限定された形式の継承をサポートします。 オブジェクト指向プログラミングの目的では、CLOS を参照します。

クラスとオブジェクト

Common Lisp は、最初に標準化されたオブジェクト言語です (1995 年に ANSI によって)。オブジェクトを扱う言語の部分は、 Common Lisp Object Systemの CLOS と呼ばれます。 CLOS の顕著な特徴は次のとおりです。

  • それはクラスシステムです (確かにプロトタイプシステムがあります)、
  • クラス間の多重継承が可能になります。
  • クラス自体はオブジェクト、またはメタクラス (クラスのクラス) のインスタンスです。
  • メタクラスの存在にリンクされたメタオブジェクト プロトコル(メタ オブジェクト プロトコル (MOP)) があり、システムのセマンティクスと動作を変更できるようになります。
  • これは、メソッドの複数の選択を提供します。つまり、必須パラメータのタプルのタイプに応じてメソッドの実行時に選択します (大多数である単純な選択言語のような特権受信者の選択ではありません)。 CLOS メソッドは、クラスに属するのではなく、汎用関数にグループ化されます。
  • これにより、メソッドの組み合わせ、つまり特定のメソッドの前および/または後に実行される補助メソッドの定義が可能になります。

CLOS では、メタクラスとクラスを定義して、実行時にオブジェクトのクラスを変更することもできます。

Common Lisp の条件システムはCLOS を使用して、実行時に発生する可能性のある条件のタイプを定義します。

一部の実装では、CLOS の拡張として、書籍『 The Art of the Metaobject Protocol』で説明されているメタオブジェクト プロトコルを提供しています。

字句関数とクロージャ

機能

Common Lisp では、関数はデータ型です。たとえば、他の関数をパラメータとして受け取り、関数を返す関数を作成することができます (これらを高階関数、またはファーストクラス関数と呼びます)。これにより、非常に一般的な演算子を作成できるようになります。

たとえば、sort 関数はシーケンスと比較演算子をパラメータとして受け取ります。あらゆる種類のデータを並べ替えるだけでなく、キーによってデータ構造を並べ替えることもできます。

 (ソート(リスト5 2 6 3 1 4 ) #' > ) ;; -> (6 5 4 3 2 1)、関数 > を比較演算子として使用します( sort ` ( ( ( 9 a ) ( 3 b ) ( 4 c ) ) ( lambda ( xy ) ( < ( first x ) ( first y ) ) ) ;; -> ((3 b) (4 c) (9 a))、つまり最初の要素でソートされたリスト

上記で定義した FOO 関数をシーケンスに適用できます。

 ( mapcar #'foo (リスト1 2 3 4 5 ) ) ;; -> (2 3 4 5 6)
名前空間

Common Lisp には、関数と変数のそれぞれに名前空間があります (たとえば、「Lisp-1」と呼ばれる Scheme とは異なります)。 Lisp-2 (またはそれ以降) には、関数名を変数名で隠すことができないという利点があります。変数にconsまたは問題なく名前を付けることができます。ただし、関数を変数として参照するには、関数 (関数 …) または上記の例のように同等の表記法 #’ を使用する必要があります。

関数と変数に加えて、block/return-from および tagbody/go 演算子のペア用に別の名前空間があります。

最後に、関数の名前空間は実際には関数自体とさまざまな種類のマクロの間で共有されることを付け加えておきます。

評価

評価モデルは単純です。評価者が式 (F A1 A2 … An) に遭遇すると、記号 F は次の項目のいずれかを表すことができます。

  1. 特殊な演算子 ( ifなど)、
  2. マクロ、
  3. 関数、つまり (defun …) で定義された関数の名前、または常に (lambda …) で示される匿名関数の名前

F が関数の場合、パラメータは左から右に連続して評価され、計算されたパラメータ値を使用して関数が呼び出されます。特殊な演算子またはマクロの場合は、状況に応じて異なります。実際、これらの演算子はパラメータの評価を制御する傾向があります。たとえば、if 演算子はすべてのパラメータを評価するわけではなく、その条件を評価し、その結果に応じて代替案の分岐を評価する必要があります。

語彙キャプチャ

字句クロージャは、その自由変数が定義されている字句環境の接続を捕捉する関数です。これにより、内部状態を含む関数を構築できるようになります (C では、内部状態を取得するためにstaticキーワードを使用しますが、字句のキャプチャは不可能です)。クロージャから単純なオブジェクト(カウンター ファクトリなど) を構築できます。

 ( defun make-counter ( ) ; make-counter は、内部値をインクリメントして表示する関数を返します( let ( ( value 0 ) ) ; ファクトリ環境では、カウンターの値を作成します( lambda ( ) ; 新しいカウンターそれ自体( incf) ) ) ;ここで、「値」への参照は、ファクトリでのその定義をキャプチャします。

その他の種類

その他の Common Lisp データ型には次のものがあります。

  • ファイルシステム内のファイルやディレクトリを表すパス名(パスを表す名前)。 Common Lisp のパス命名ツールは、ほとんどのオペレーティング システムの命名規則よりも一般的であるため、Lisp プログラムによるファイルへのアクセスは、さまざまなシステム間でほぼ移植可能です。
  • 入力ストリームと出力ストリームは、ターミナルや開いているファイルなどのバイナリ データとテキスト データのソースとシンクを表します。
  • Common Lisp には独自の擬似乱数生成器があります。 Random Stateオブジェクトは擬似乱数の再利用可能なソースを表し、ユーザーがジェネレーターを初期化したり、シーケンスを強制的に再生したりできるようにします。
  • 条件は、プログラムが応答できる必要があるエラー、例外、その他の「興味深い」イベントを表すために使用される特別なタイプです。 Common Lisp には、最も包括的な例外処理システムの 1 つがあります。エラー後の回復が可能になります。

Common Lisp には、オブジェクト指向プログラミング用のツールキットである Common Lisp Object System (CLOS) も組み込まれています。したがって、無限の数のタイプを追加することが可能です。

  1. كومون ليسب – arabe
  2. Common Lisp – bulgare
  3. Common Lisp – tchèque
  4. Common Lisp – danois
  5. Common Lisp – allemand
  6. Common Lisp – anglais

Common Lispについて詳しく解説・関連動画

サイエンス・ハブ

知識の扉を開け、世界を変える。