Tennent'in Yazışma İlkesi'nin iyi açıklaması nedir?


21

Kendimi bu ilkenin neyle ilgili olduğunu ve dil tasarımı için neden bu kadar önemli olduğunu görmek için mücadele ederken buldum.

Temel olarak, exprdilde her ifade için tam olarak bu yapıyla aynı olması gerektiğini belirtir :

(function () { return expr; })()

Ayrıca, Ruby'nin bu prensibi yerine getirdiğini duydum, Python ise. Bunun neden doğru olduğunu veya hiç doğru olup olmadığını anlamıyorum.


3
Neden konu dışı olduğunu anlayamıyorum, biri bana açıklayabilir mi?
Andrew,

3
Birkaç sorun var; Ona dokundum ve programcılara gönderiyorum, bunun gibi tartışmalar biraz daha hoş karşılanıyor.
Ripped Off

1
Ruby bu ilkeye uymuyor: exprMevcut yığın izini aldığını varsayalım .
Landei

Yanıtlar:


18

"Tennent'in Yazışma Prensibi" nden önce hiç duymamıştım ve dil tasarımında daha az önem taşıyordum. İfadelerin googling yapması, 2006'nın, ne düşündüğünü ve kapanışlar için de nasıl uygulanması gerektiğini düşündüğünü ortaya koyan bir Neal Gafter bloguna öncülük ediyor gibi görünüyor. Ve forumlardaki diğer çoğu, Gafter'ın girişine atıfta bulunuyor gibi görünüyor.

Bununla birlikte, Douglas Crockford ("bildiğim ve güvendiğim bir isim") tarafından "TCP" denilen bir söz: http://java.sys-con.com/node/793338/ . Kısmen

Tennent'in Yazışma İlkesi (veya TCP) iddiasının savunucularının kötü bir koku belirtisi olduğu dönüş beyanları ve break ifadeleri gibi bu şekilde eklenemeyen bazı şeyler vardır. Yow! Dil tasarımı zaten koku alma halüsinasyonlarıyla başa çıkmadan yeterince zor. Böylece sorunu daha iyi anlayabilmek için, Tennent'in 1981 tarihli Programlama Dilleri Kitabı'nın bir kopyasını aldım.

Bu Yazışmalar Prensibi olduğu ortaya çıktı açıklayıcı değil kuralcı . Değişken tanımlar ve işlem parametreleri arasında bir yazışma göstererek (şimdiye kadar unutulmuş) Pascal programlama dilini analiz etmek için kullanır. Tennent, geri dönüş beyanlarının yazılmamasını bir sorun olarak tanımlamıyor .

Öyleyse, "Tennent'in Yazışma Prensibi" ismi yanlış kullanılmış ve Neal'ın bahsettiği her ne olursa olsun "Gafter'in Düşünsel ve Muhtemelen Genelleştirilmiş TCP" olarak adlandırılmalıdır. Her halükarda, baskısı tükenmiş bir kitap adı perdesinin arkasına saklanmak için yeterli değil


1
Gafter'in Düşünsel ve Muhtemelen Genelleştirilmiş TCP'si için +1
jcora

9

Bunu, iyi tasarlanmış bir dilin, bir programcının doğal olarak beklediği gibi yaptığı genel kuralın bir parçası olarak görüyorum. Bir kapamaya yeniden düzenlemek istediğim bir kod bloğum varsa ve bu bloğu tek tek kod satırları hakkında gerçekten düşünmeden uygun sözdizimiyle sarsam, o zaman bu bloğun kapağında olduğu gibi aynı şeyi yapmasını bekliyorum. satır içi yaptım. Bazı ifadeler "this" anahtar kelimesini (belki de örtük şekilde) kullanıyorsa ve dil "bu" kelimesini kapağın içinde kullanıyorsa, kapatmayı tanımlayan yöntemi tanımlayan sınıf yerine onu temsil etmek için kullanılan adsız bir sınıfa, yani bu ifadeler değişti, kod bloğum artık düşündüğüm şeyi yapmıyor ve bir hatayı izlemem ve kodumun kapatılması için nasıl değiştirileceğini bulmam gerekiyor.

Sorun, kapanışları çıkarabilecek, olası sorunları tespit edebilecek ve hatta sorunları çözmek için çıkarılan kodu otomatik olarak ayarlayabilen akıllı yeniden düzenleme araçlarına sahip bir IDE ile de hafifletilebilir.


3

Claus Reinke: Tennent'in "Semantik Prensiplere Dayalı Dil Tasarımı"
ile ilgili ilkelerin ilginç bir yorumunu verir:
"Yazışma, şunu söylememize izin veren ilkedir

let(this=obj, x=5) { .. }  

ve

((function(x) { .. }).call(obj,5))  

eşdeğer olmalı ve resmi parametre listelerinde yapabileceğimiz her şeyi yapmalıyız, ayrıca bildirimlerde de yapabiliriz ve bunun tersi de. "[ayrıca bkz. aşağıda Reinke].

RD Tennent: Anlamsal ilkelere dayanan
dil tasarım yöntemleri "Dil anlambilimine yönelik programlama yaklaşımından türetilen ilkelere dayanan iki dil tasarım yöntemi Pascal diline bir uygulama ile tanımlanmış ve gösterilmiştir. İlkeler, ilk olarak parametrik ve arasındaki ilişkidir. bildirim mekanizmaları ve ikincisi, küme teorisinden uyarlanmış programlama dilleri için bir soyutlama ilkesidir. Pascal'ın çeşitli yararlı uzantıları ve genellemeleri, dizi parametresi problemine bir çözüm ve bir modülerleştirme tesisi de dahil olmak üzere bu ilkeleri uygulayarak ortaya çıkar. "

Claus Reinke: Haskell'de "İşlevsel programlama, dil tasarımı ve ısrarla ilgili"



2

Tennent'in CP'sinin dil tasarımı için neden bu kadar önemli olduğu sorusunu yanıtlamak için Neal Gafter'den alıntı yapmak istiyorum :

Tennent'in ilkeleri çok güçlü çünkü ihlalleri dilde kusurlar, usulsüzlükler, gereksiz kısıtlamalar, beklenmedik etkileşimler veya komplikasyonlar vb.

TCP'nin herhangi bir ihlali, kapanma kodu gibi çalışmaların kapanmasını beklediğinde gelecekte bazı programcılara zarar verebilir, ancak TCP ihlali durumunda kullanmayacaklarını bulur.


1

RE Python bu prensibi takip etmiyor. Genellikle prensibi izler. Temel örnek:

>>> x = ['foo']
>>> x
['foo']
>>> x = (lambda: ['foo'])()
>>> x
['foo']

Ancak, Python ifadeleri ve ifadeleri ayrı ayrı tanımlar . Yana ifdallar, whiledöngüler, yıkıcı atama ve diğer ifadeleri de kullanılamaz lambdahiç ifadeler, Tennent ilkesinin mektup kendileri için geçerli değildir. Buna rağmen, kendini yalnızca Python ifadeleriyle sınırlandırmak hala bir Turing komple sistemi üretiyor. Bu yüzden bunu ilkenin ihlali olarak görmüyorum; veya daha doğrusu, prensibi ihlal ederse, ifadeleri ve ifadeleri ayrı ayrı tanımlayan hiçbir dil ilkeye uymayabilir.

Ayrıca, lambdaifadenin gövdesi yığın izini yakalıyorsa veya VM'de başka bir gözden geçirme gerçekleştiriyorsa, bu farklılıklara neden olabilir. Ancak bence bu ihlal olarak sayılmamalıdır. Eğer exprve (lambda: expr)() mutlaka aynı baytkoduna derlemek, sonra prensip gerçekten derleyiciler değil semantik ilgilidir; ancak farklı byte kodlarını derleyebiliyorlarsa, VM durumunun her durumda aynı olmasını beklememeliyiz.

Tennent ilkesinin ihlal edilmediğine inandığım halde, anlama sözdizimini kullanarak bir sürprizle karşılaşılabilir. Örnek:

>>> [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]

Sürpriz, liste kavramalarının nasıl tanımlandığının bir sonucudur. Yukarıdaki “sürpriz” anlayışı bu koda eşdeğerdir:

>>> 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]

Bu şekilde görülüyorsa, yukarıdaki “sürpriz” anlayışı daha az şaşırtıcıdır ve Tennent ilkesinin ihlali değildir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.