私は、この原則が何であり、言語設計にとってそれが非常に重要であるのかを理解するのに苦労しています。
基本的に、すべての式に対して expr
言語の、この構造とまったく同じである必要があると述べています。
(function () { return expr; })()
また、Rubyはこの原則に従うが、Pythonは従わないと聞いた。これがなぜ真実なのか、それともまったく真実なのかはわかりません。
expr
。現在のスタックトレースを取得すると仮定します。
私は、この原則が何であり、言語設計にとってそれが非常に重要であるのかを理解するのに苦労しています。
基本的に、すべての式に対して expr
言語の、この構造とまったく同じである必要があると述べています。
(function () { return expr; })()
また、Rubyはこの原則に従うが、Pythonは従わないと聞いた。これがなぜ真実なのか、それともまったく真実なのかはわかりません。
expr
。現在のスタックトレースを取得すると仮定します。
回答:
「Tennent's Correspondence Principle」のことは聞いたことがなく、言語設計で重要なことはほとんどありません。表現のグーグルはすべて、2006年のNeal Gafterのブログの1つにつながり、彼がそれが何であるか、そしてそれがクロージャーにも適用されるべきだと考える方法を説明しているようです。そして、フォーラムの他のすべてのほとんどは、Gafterのエントリーを参照しているようです。
ただし、ダグラス・クロックフォードによる「TCP」についての言及(私が知っている信頼できる名前):http : //java.sys-con.com/node/793338/。ある程度
Tennentの通信原理(またはTCP)の主張者が悪臭の症状であると主張するreturnステートメントやbreakステートメントなど、そのように囲まれないものがいくつかあります。うん!嗅覚の幻覚に対処することなく、言語設計はすでに十分に困難です。そこで問題をよりよく理解するために、私はTennentの1981年の本、Principles of Programming Languagesのコピーを購入しました。
通信原理は規範的ではなく記述的であることが判明しました。彼はこれを使用して(今では忘れられている)Pascalプログラミング言語を分析し、変数の定義とプロシージャのパラメーターの対応を示します。Tennentは、returnステートメントの対応の欠如を問題として特定していません。
そのため、「Tennent's Correspondence Principle」という名前は誤って使用されているようです。いずれにしても、絶版の本の名前のカーテンの後ろに隠れるのに十分ではありません
これは、適切に設計された言語がプログラマーが自然に期待することを行うという一般的なルールの一部と考えています。クロージャーにリファクタリングしたいコードのブロックがあり、個々のコード行を実際に考えずに適切な構文でそのブロックをラップする場合、そのブロックはクロージャーでそれと同じことをすることを期待していますインラインでした。一部のステートメントがキーワード「this」(おそらく暗黙的に)を使用し、言語がクロージャー内で使用される「this」を、クロージャーを定義するメソッドを定義するクラスではなく、それを表すために使用される匿名クラスを参照させる場合、これらのステートメントは変更され、私のコードブロックは思ったとおりに動作しなくなり、バグを追跡し、クロージャーで機能するようにコードを変更する方法を見つけ出す必要があります。
また、スマートリファクタリングツールを備えたIDEを使用して問題を軽減することもできます。このツールは、クロージャを抽出し、潜在的な問題を検出し、抽出されたコードを自動的に調整して問題を解決できます。
Claus Reinke:Tennentの「セマンティック原則に基づいた言語設計」について
、原則の興味深い解釈を示し
ています。「対応は、
let(this=obj, x=5) { .. }
そして
((function(x) { .. }).call(obj,5))
同等である必要があり、正式なパラメータリストでできることはすべて、宣言でも行うことができ、その逆も可能です。」[以下のReinkeも参照してください。]
RD Tennent:セマンティック原則に基づく言語設計方法
「プログラミング言語セマンティクスへの表示的アプローチから派生した原則に基づく2つの言語設計方法は、言語Pascalへのアプリケーションによって記述および図示されます。原則は、まず、パラメトリックと宣言的メカニズム、そして第二に、集合理論から適応したプログラミング言語の抽象化の原理。Pascalのいくつかの有用な拡張と一般化は、これらの原理を適用することで生まれます。
Claus Reinke:Haskellの「関数型プログラミング、言語設計、永続化について」
TennentのCPが言語設計にとって非常に重要である理由の質問に答えるために、Neal Gafterを引用したいと思います。
Tennentの原則は非常に強力です。なぜなら、それらの違反は、言語に欠陥、不規則性、不必要な制限、予期しない相互作用または合併症などとして現れる傾向があるからです。
TCPの違反は、クロージャーが非クロージャーコードのように機能することを期待しているが、TCPに違反して機能しないことがわかったプログラマーを将来傷つける可能性があります。
RE Pythonはこの原則に従っていません。通常、原則に従います。基本的な例:
>>> x = ['foo']
>>> x
['foo']
>>> x = (lambda: ['foo'])()
>>> x
['foo']
ただし、Pythonは式とステートメントを別々に定義します。以来if
枝、while
ループ、破壊的代入やその他の文がで使用することはできませんlambda
すべての表現、Tennent原理の手紙は、彼らには適用されません。それでも、Python式のみの使用に制限すると、チューリング完全システムが生成されます。したがって、これは原則に違反しているとは思わない。むしろ、原則に違反する場合、ステートメントと表現を別々に定義する言語は原則に準拠できません。
また、lambda
式の本体がスタックトレースをキャプチャしているか、VMで他のイントロスペクションを実行している場合、違いが生じる可能性があります。しかし、私の意見では、これは違反としてカウントされるべきではありません。場合expr
と(lambda: expr)()
必ずしも同じバイトコードにコンパイルし、その後、原則は本当にコンパイラではないセマンティクスに関する。ただし、異なるバイトコードにコンパイルできる場合、VMの状態がそれぞれ同じになるとは考えないでください。
理解構文を使用すると、驚きに遭遇する可能性がありますが、これはTennentの原則にも違反しているとは思いません。例:
>>> [x for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [f() for f in [lambda: x for x in xrange(10)]] # surprise!
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
>>> # application of Tennent principle to first expression
... [(lambda: x)() for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [f() for f in [(lambda x: lambda: x)(x) for x in xrange(10)]] # force-rebind x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> map(lambda f:f(), map(lambda x: lambda: x, xrange(10))) # no issue with this form
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
驚きは、リストの内包表記がどのように定義されているかの結果です。上記の「驚き」の理解は、このコードと同等です。
>>> result = []
>>> for x in xrange(10):
... # the same, mutable, variable x is used each time
... result.append(lambda: x)
...
>>> r2 = []
>>> for f in result:
... r2.append(f())
...
>>> r2
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
このように見れば、上記の「驚き」の理解はそれほど驚くことではなく、Tennantの原則に違反するものではありません。