2010-12-27 11 views
10

私は、Lispプログラムの解釈/コンパイル中の "読者"の目的を、おそらくより正確には疑問に思っています。Lisp解釈中の "読者"の仕事は何ですか?

私がやった前回の質問の研究から、読者(この場合はClojureにとって特に)は "構文的なプリプロセッサ"と考えることができます。主な任務は、読者のマクロとプリミティブフォームの拡張です。したがって、二つの例:

'cheese   --> (quote cheese) 
{"a" 1 "b" 2} --> (array-map "a" 1 "b" 2) 

ので、リーダが(S式からなる)プログラムのテキストを取り込み、その後、直接評価することができるメモリ内のデータ構造を構築し、返します。

これは真実からどのくらい離れていますか(プロセス全体を過度に単純化しましたか)?読者は他にどんなタスクを実行しますか? Lispsの美徳が同型性(データとしてのコード)であると考えると、なぜそれが実際に読者の仕事に匹敵するのであれば、語彙分析が必要なのでしょうか?

ありがとうございます!

答えて

20

一般に、Lispの読者はs式を読み込み、データ構造を返します。 READはI/O操作です。入力は文字ストリームで、出力はLispデータです。

プリンタは、逆のことをします。つまり、Lispデータを取り込んで文字列として出力します。したがって、外部のS式にLispデータを出力することもできます。

解釈は、インタプリタによってコードを実行することを意味します。しかし、多くのLispシステム(Clojureを含む)はコンパイラを使用しています。 Lispフォームの値を計算するタスクは通常評価と呼ばれます。評価は、解釈、コンパイル、または両方を組み合わせて行うことができます。

S-Expression:記号式。データの外部、テキスト表現。外部は、テキストファイルや文字列などに見られるs式を意味します。したがって、s式は、一般的には外部のメディアの文字で構成されています。

Lispのデータ構造:シンボル、リスト、文字列、数値、文字、...

リーダー:S式を読み取り、Lispのデータ構造を返します。

また、s式はLispソースコードをエンコードするためにも使用されることに注意してください。

いくつかのLisp方言では、読者はプログラマブルでテーブル駆動型です(いわゆるreadテーブル経由)。この読み込みテーブルには、文字の読者関数が含まれています。例えば、クォートの文字は、式を読み込んで(list 'quote expression)の値を返す関数にバインドされています。数値0..9は、数値を読み取る関数にバインドされています(実際には、いくつかのリスプでは数値が異なる基底で読み取られるため、これはもっと複雑かもしれません)。

S式は、データ構造の外部構文を提供します。

Lispプログラムは、s式を使用して外部形式で記述されます。しかし、すべてのs式が有効なLispプログラムであるわけではありません:Lispの構文は通常Lispデータの上に定義されます。

IFは、例えば(Common Lispのhttp://www.lispworks.com/documentation/HyperSpec/Body/s_if.htm中)の構文は次のとおりです。

if test-form then-form [else-form] 

だから、テストの形式、当時のフォームとオプションの他に、フォームを期待しています。

としてS式次の式のIF有効です。

(if (foo) 1 2) 
(if (bar) (foo)) 

しかし、Lispプログラムは、フォームなので、我々はまた、Lispプログラムを使用してこれらのフォームを構築することができます。

(list 'の場合'(FOO )1 2)は、有効なIF形式を返すLispプログラムです。

CL-USER 24 > (describe (list 'if '(foo) 1 2)) 

(IF (FOO) 1 2) is a LIST 
0  IF 
1  (FOO) 
2  1 
3  2 

このリストは、たとえばEVALで実行できます。 EVALはリスト形式を期待しています - s式ではありません。 s式は外部表現であることを覚えておいてください。 Lispフォームを作成するには、それを読む必要があります。

コードはデータと言われています。 Lispフォームは、リスト、シンボル、数字、文字列などの内部Lispデータ構造として表現されます。他の多くのプログラミング言語では、コードは生のテキストです。 Lispでは、s-expressionsは生のテキストです。関数READで読み取ると、s式はデータに変換されます。

したがって、Lispのトップレベルの基本的なやり取りは、REPL、Eval Print Loopの読み取りと呼ばれます。 これは、繰り返しの発現を読み取るループであるLispの形状を評価し、それを印刷:

READ : s-expression -> lisp data 
EVAL : lisp form -> resulting lisp data 
PRINT: lisp data -> s-expression 

だから最も原始的なREPLである:

したがって
(loop (print (eval (read)))) 

ビューの概念的な観点から、あなたの質問に答えるために、評価の間、読者は何もしません。評価には関係しません。評価は関数EVALによって行われます。リーダーはREADの呼び出しによって呼び出されます。 EVALはLispデータ構造を入力として使用するので(s式ではない)、リーダはLispフォームが評価される前に実行されます(たとえば、解釈またはコンパイルと実行によって)。

+3

すてきな説明をありがとう。つまり、読者がプログラムデータをS式として構造化されたプレーンテキストとして読み込み、Lispデータ構造体を返すと言うかもしれません。これらの表現は評価されませんが、単に効果的に評価できる方法でそれらを表現します。 評価者(シンプルなLisp-in-lispエバリュエータが提示されているSICPの "metacircular abstraction"の章による)と本格的なインタプリタの違いをより明確に見ています。 – Andrew

+4

@Andrew:そうです。一般的に読者は物事を評価しません。これは、s式用のLispデータ構造を作成するだけです。評価者は、これらの内部データ構造を解釈できるようになりました。レクサー段階はすでに完了しています。多くの場合、データとしてのこれらのプログラムは、中間ステップでマシンコードまたはバイトコードにコンパイルされます。例えば、Common Lispの読者は物事を評価する機能を持っていることにも注意してください。 '(1 2#。(+ 1 2))は(1 2 3)を返します。 #。読み取り時に次の式を評価するリーダマクロです。読取り表を介して追加の動作を実装することもできます。 –

関連する問題