私は今LISPを勉強しています。 「リスト」と「S式」という2つの用語に遭遇しました。私はそれらを区別することができません。それらはLispの単なる同義語ですか?
まず、すべてのS式がリストを表すわけではありません。裸の原子を表すfoobar
などの式も、S式と見なされます。 「conscell」構文と同様に、(car . cons)
は、「cons」部分自体が別のリスト(またはnil)ではない場合に使用されます。 (a b c d)
などのより一般的なリスト式は、ネストされたconsセルのチェーンの単なる構文糖衣です。その例は(a . (b . (c . (d . nil))))
に展開されます。
次に、「S式」という用語は構文 --(items like this (possibly nested))
を指します。そのようなS式はリストのLISPソースコードの表現ですが、技術的にはリスト自体ではありません。この区別は、10進数のシーケンスとその数値の間、または引用符内の文字のシーケンスと結果の文字列の間の区別と同じです。
それはおそらく過度に技術的な違いです。プログラマーは、値自体が値であるかのように、値のリテラル表現を日常的に参照します。しかし、LISPとリストでは、LISPプログラムのすべては技術的にはリストであるため、状況は少し複雑になります。
たとえば、次の式について考えてみます。
(+ 1 2)
上記は、アトム+
、1
、および2
で構成されるフラットリストを表す単純なS式です。
ただし、LISPプログラム内では、このようなリストは、引数として1と2を使用した+
関数の呼び出しとして解釈されます。 (S-expressionではなくlistであることに注意してください。これは、そのように解釈されます。評価者には、ソースではなく、リーダーによって事前に解析されたリストが渡されます。コードテキスト。)
したがって、上記のS式はリストを表しますが、LISPプログラムのコンテキストで「リスト」として参照になることはめったにありません。マクロや読者の内部の仕組みについて議論したり、他のコード生成や構文解析のコンテキストのためにメタ構文の議論に従事したりしない限り、典型的なLISPプログラマーは代わりに上記を数値式として扱います。
一方、次のS式のいずれかはおそらくwould「リスト」と呼ばれます。LISPコードとして評価すると、ランタイムとして上記のリテラルS式で表されるリストが生成されるためです。値:
'(+ 1 2)
(quote (+ 1 2))
(list '+ 1 2)
もちろん、コードとデータの同等性はLISPの優れた点の1つであるため、区別は流動的です。しかし、私のポイントは、上記のすべてがS式とリストであるのに対し、カジュアルなLISPでは「リスト」と呼ばれるのは一部だけであるということです。
S式はデータの表記です。
歴史的に、s式(記号式の略)は次のように記述されます。
FOO
やBAR
のような記号(
_expression-1_.
_ 式-2_)
_NIL
(
_ A
_.
_ _(
_ B
_.
_ NIL
_)
_ _)
_はリストとして記述された方が簡単です_(A B)
_また、歴史的にプログラムのテキストは異なって書かれていることにも注意してください。関数ASSOC
の例。
_assoc[x;y] =
eq[caar[y];x] -> cadar[y];
T -> assoc[x;cdr[y]]
_
歴史的に、これらのm式(メタ式の略)からS式へのマッピングも存在していました。今日、ほとんどのLISPプログラムコードはS式を使用して記述されています。
これはここで説明されています: マッカーシー、シンボリック式の再帰関数
最近のCommonLISPのようなLISPプログラミング言語ではs-expressionsはより多くの構文を持ち、より多くのデータ型をエンコードできます。
symbol123
_、_|This is a symbol with spaces|
_123
_、_1.0
_、_1/3
_、.。"This is a string"
_#\a
_、_#\space
_#(a b c)
( a . b )
_、_(a b c)
_; this is a comment
_、_#| this is a comment |#
_もっと。
リスト
リストはデータ構造です。これは、consセルとリスト終了マーカーで構成されます。リストには、LISPでS式のリストとして表記があります。リストには他の表記法を使用することもできますが、LISPでは、リストを記述するためにS式構文を使用することにしました。
サイドノート:プログラムとフォーム
Common LISPのようなプログラミング言語では、プログラミング言語の表現はテキストではなくデータです。これは、他の多くのプログラミング言語とは異なります。プログラミング言語のCommonLISPでの式は、_LISP forms
_と呼ばれます。
たとえば、関数呼び出しはLISPデータであり、呼び出しは最初の要素として関数記号を含むリストであり、次の要素はその引数です。
それを_(sin 3.0)
_と書くことができます。しかし、それは本当にデータです。構築できるデータ。
LISPフォームを評価する関数はEVAL
と呼ばれ、プログラムテキストやプログラムテキストの文字列ではなく、LISPデータを受け取ります。したがって、LISPデータを返すLISP関数を使用してプログラムを構築できます。_(EVAL (LIST 'SIN 3.0))
_は_0.14112
_に評価されます。
LISPフォームにはデータ表現があるため、通常はLISPの外部データ表現を使用して記述されます。これは何ですか。 -S式!
S式です。 LISPデータとしてのLISPフォームは、S式として外部に書き込まれます。
最初にLISPの主な機能を理解する必要があります-プログラムはデータとして操作できます。他の言語(CやJavaなど)とは異なり、特別な構文({
、}
、class
、define
など)、LISPではコードを(ネストされた)リストとして記述します(ところで、これにより 抽象構文木 を直接表現できます) 。繰り返しますが、言語のデータ構造と同じように見えるプログラムを作成します。
あなたがそれをデータとして話すとき、あなたはそれを "リスト"と呼びます、しかしあなたがプログラムコードについて話すときは、用語 "s-expression"。したがって、技術的には類似していますが、異なるコンテキストで使用されます。これらの用語が混在する唯一の実際の場所は、メタプログラミング(通常はマクロを使用)です。
また、s-expressionは、atom(数値、文字列など)のみで構成されている場合もあることに注意してください。
S式の簡単な定義は次のとおりです。
(define S-expression?
(λ (object)
(or (atom? object) (list? object))))
;; Where atom? is:
(define atom?
(λ (object)
(and (not (pair? object)) (not (null? object)))))
;; And list? is:
(define list? (λ (object)
(let loop ((l1 object) (l2 object))
(if (pair? l1)
(let ((l1 (cdr l1)))
(cond ((eq? l1 l2) #f)
((pair? l1) (loop (cdr l1) (cdr l2)))
(else (null? l1))))
(null? l1)))))
どちらも同じように書かれています:(何とか何とか何とか)、入れ子にすることができます。 1つの違いがあります-リストの前にはアポストロフィが付いています。
評価について:
必要に応じて、リストをs-expに、またはその逆に変換できます。
IAS: