68

私はリチャード・ストールマンによる次の声明に遭遇しました:

'Lispシステムを起動すると、read-eval-printループに入ります。他のほとんどの言語には、readに匹敵するもの、evalに匹敵するもの、printに匹敵するものはありません。なんとギャップのある欠陥でしょう。'

今、私はLispでほとんどプログラミングをしませんでしたが、Pythonでかなりの量のコードを書き、最近ではErlangで少し書きました。私の印象では、これらの言語はread-eval-printループも提供しますが、ストールマンは(少なくともPythonについては)同意しません。

「Pythonのドキュメントは、基本的にLispに似ていると人々が言っ​​た後、ざっと読みました。私の結論はそうではないということです。Lispを起動すると、「read」、「eval」、「print」が実行されますが、これらはすべてPythonにはありません。

LispとPythonのread-eval-printループの間に本当に根本的な技術的な違いがありますか?Lisp REPLが簡単にし、Pythonでは難しいことの例を挙げていただけますか?

4

4 に答える 4

62

Stallmanの立場を支持して、Pythonは以下の分野で典型的なLispシステムと同じことをしません:

  • Lispのread関数は、S式を読み取ります。これは、データとして扱うことも、コードとして評価することもできる任意のデータ構造を表します。Pythonで最も近いものは、単一の文字列を読み取ります。これを意味する場合は、自分で解析する必要があります。

  • Lispのeval関数は、任意のLispコードを実行できます。evalPythonの関数は式のみexecを評価し、ステートメントを実行するにはステートメントが必要です。しかし、これらは両方ともテキストとして表されるPythonソースコードで機能するため、PythonASTを「評価」するには一連のフープをジャンプする必要があります。

  • Lispの関数は、受け入れるprintのとまったく同じ形式でS式を書き出します。Pythonでは、印刷しようとしているデータによって定義されたものを印刷しますが、これは常に元に戻せるとは限りません。readprint

明らかにPythonには正確にとという名前の関数evalがありますprintが、それらは彼が期待するものとは異なる(そして劣った)何かをするので、ストールマンの声明は少し不誠実です。

私の意見では、PythonにLispに似たいくつかの側面があり、ストールマンがPythonを調べることを人々が推奨した理由を理解できます。ただし、PaulGrahamが「Lispを差別化したもの」で論じているように、Lispのすべての機能を含むプログラミング言語もLispでなければなりませ

于 2012-09-03T19:45:57.547 に答える
33

Stallmanのポイントは、明示的な「リーダー」を実装しないと、REPLプロセスから重要なステップが削除されるため、PythonのREPLがLispsと比較して機能しなくなったように見えることです。Readerは、テキスト入力ストリームをメモリに変換するコンポーネントです。言語に組み込まれ、ソースコードデータの両方に使用されるXMLパーサーのようなものを考えてみてください。これは、マクロを作成する場合(理論的には、モジュールを使用してPythonで可能ast)だけでなく、デバッグやイントロスペクションにも役立ちます。

incf特別なフォームがどのように実装されているかに興味があるとします。次のようにテストできます。

[4]> (macroexpand '(incf a))
(SETQ A (+ A 1)) ;

ただし、incfシンボル値をインクリメントする以上のことができます。ハッシュテーブルエントリをインクリメントするように求められた場合、正確には何をしますか?どれどれ:

[2]> (macroexpand '(incf (gethash htable key)))
(LET* ((#:G3069 HTABLE) (#:G3070 KEY) (#:G3071 (+ (GETHASH #:G3069 #:G3070) 1)))
 (SYSTEM::PUTHASH #:G3069 #:G3070 #:G3071)) ;

ここでは、このCommonLispシステムの実装の詳細であるincfシステム固有の関数を呼び出すことを学びます。puthash「プリンタ」が「リーダー」に知られている機能をどのように利用しているかに注意してください。たとえば、#:構文で匿名シンボルを導入したり、拡張式のスコープ内で同じシンボルを参照したりします。Pythonでこの種の検査をエミュレートすると、はるかに冗長になり、アクセスしにくくなります。

REPLでの明らかな使用法に加えて、経験豊富なLispersは、XMLやjsonに匹敵する、シンプルですぐに利用できるシリアル化ツールとして、コードで使用printしています。readPythonにはstrLispと同等の関数がありますが、に相当するprintものがなくread、最も近いものはevalです。evalもちろん、解析と評価という2つの異なる概念を統合します。これは、このような問題とこのような解決策につながり、Pythonフォーラムで繰り返し発生するトピックです。読者と評価者がきれいに分離されているので、これはLispでは問題にはなりません。

最後に、リーダー機能の高度な機能により、プログラマーは、マクロでさえ提供できない方法で言語を拡張できます。このような困難なことを可能にする完璧な例はinfix Mark Kantrowitzによるパッケージであり、リーダーマクロとしてフル機能のインフィックス構文を実装しています。

于 2012-09-03T20:01:04.187 に答える
22

Lispベースのシステムでは、通常、REPL(read eval print loop)から実行中にプログラムを開発します。したがって、それはたくさんのツールを統合します:完了、エディター、コマンドラインインタープリター、デバッガー、...デフォルトはそれを持っていることです。エラーのある式を入力します-いくつかのデバッグコマンドが有効になっている別のREPLレベルにいます。あなたは実際にこの振る舞いを取り除くために何かをしなければなりません。

REPLの概念には2つの異なる意味があります。

  • Lisp(または他のいくつかの同様の言語)のようなRead EvalPrintLoop。プログラムとデータを読み取り、結果データを評価して印刷します。Pythonはこのようには機能しません。LispのREPLを使用すると、メタプログラミングの方法で直接作業し、生成(コード)、展開のチェック、実際のコードの変換などを行うコードを記述できます。Lispのトップループは読み取り/評価/印刷です。Pythonには、トップループとしてreadstring / Evaluation/printstringのようなものがあります。

  • コマンドラインインターフェイス。インタラクティブシェル。たとえば、IPythonについてはを参照してください。それをCommonLispのSLIMEと比較してください。

デフォルトモードのPythonのデフォルトシェルは、インタラクティブに使用するにはそれほど強力ではありません。

Python 2.7.2 (default, Jun 20 2012, 16:23:33) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a+2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> 

エラーメッセージが表示され、それだけです。

それをCLISPREPLと比較してください。

rjmba:~ joswig$ clisp
  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Welcome to GNU CLISP 2.49 (2010-07-07) <http://clisp.cons.org/>

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010

Type :h and hit Enter for context help.

[1]> (+ a 2)

*** - SYSTEM::READ-EVAL-PRINT: variable A has no value
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of A.
STORE-VALUE    :R2      Input a new value for A.
ABORT          :R3      Abort main loop
Break 1 [2]> 

CLISPはLispの条件システムを使用してデバッガREPLに侵入します。それはいくつかの再起動を提示します。エラーコンテキスト内で、新しいREPLは拡張コマンドを提供します。

再起動を使用してみましょう:R1

Break 1 [2]> :r1
Use instead of A> 2
4
[3]> 

したがって、プログラムのインタラクティブな修復と実行の実行が可能になります...

于 2012-09-03T20:03:07.377 に答える
7

Pythonのインタラクティブモードは、Pythonの「ファイルからコードを読み取る」モードとは、言語のテキスト表現に固有の、いくつかの小さな重要な点で異なります。Pythonも同像性ではなく、「read-eval-printloop」ではなく「interactivemode」と呼んでいます。それはさておき、種類の違いというよりはグレードの違いだと思います。

さて、実際には「種類の違い」に近いものがあります。Pythonコードファイルでは、空白行を簡単に挿入できます。

def foo(n):
  m = n + 1

  return m

同じコードをインタープリターに貼り付けようとすると、関数は「閉じられている」と見なされ、間違ったインデントに裸のreturnステートメントがあると文句を言います。これは(Common)Lispでは起こりません。

さらに、Common Lisp(CL)には、Pythonでは(少なくとも私が知る限りでは)利用できない便利な変数がいくつかあります。CLとPythonの両方に「最後の式の値」(*CL、_Python)がありますが、CLには**(最後の前の式の値)と***(その前の式の値)と+、、(式自体)もあります。CLはまた、式とステートメントを区別せず(本質的に、すべてが式です)、これらすべてが、はるかに豊かなREPLエクスペリエンスの構築に役立ちます。+++++

冒頭で申し上げましたように、種類の違いというよりはグレードの違いです。しかし、それらの間のギャップがほんの少し広いだけだったとしたら、それはおそらく種類の違いでもあるでしょう。

于 2012-09-07T13:53:20.120 に答える