Saya menemukan diri saya berjuang untuk melihat apa prinsip ini dan mengapa begitu penting untuk desain bahasa.
Pada dasarnya, ini menyatakan, bahwa untuk setiap ekspresi expr
dalam bahasa harus persis sama dengan konstruksi ini:
(function () { return expr; })()
Juga, saya telah mendengar bahwa Ruby mematuhi prinsip ini, sementara Python tidak. Saya tidak mengerti mengapa ini benar, atau jika itu benar sama sekali.
design
language-agnostic
Andrew
sumber
sumber
expr
mendapat jejak stack saat ini.Jawaban:
Saya belum pernah mendengar tentang "Prinsip Korespondensi Tennent" dan bahkan kurang penting dalam desain bahasa. Googling ekspresi tampaknya semua mengarah ke satu blog Neal Gafter tahun 2006 yang menetapkan apa yang dia pikirkan dan bagaimana menurutnya itu harus diterapkan pada penutupan juga. Dan kebanyakan semua orang di forum tampaknya merujuk pada entri Gafter.
Namun di sini disebutkan "TCP" dari Douglas Crockford (nama yang saya tahu dan percayai): http://java.sys-con.com/node/793338/ . Dalam bagian
Karenanya tampaknya nama "Prinsip Korespondensi Tennent" salah digunakan, dan apa pun yang dibicarakan Neal mungkin harus disebut "Gafter's Imagined and Possiblely Generalized TCP" ... atau semacamnya. Dalam hal apa pun tidak cukup untuk bersembunyi di balik tirai nama buku yang tidak dicetak
sumber
Saya melihat ini sebagai bagian dari aturan umum bahwa bahasa yang dirancang dengan baik melakukan apa yang diharapkan oleh seorang programmer. Jika saya memiliki blok kode yang ingin saya refactor menjadi penutupan, dan saya membungkus blok itu dengan sintaks yang tepat tanpa benar-benar memikirkan baris kode individu, maka saya berharap bahwa blok melakukan hal yang sama di penutupan seperti itu lakukan inline. Jika beberapa pernyataan menggunakan kata kunci "ini" (mungkin secara implisit) dan bahasanya membuat "ini" yang digunakan di dalam penutupan merujuk ke kelas anonim yang digunakan untuk mewakilinya daripada kelas yang mendefinisikan metode yang menentukan penutupan, maka arti dari pernyataan-pernyataan itu telah berubah, blok kode saya tidak lagi melakukan apa yang saya pikirkan, dan saya harus melacak bug dan mencari tahu bagaimana mengubah kode saya untuk bekerja di penutupan.
Masalahnya juga dapat dikurangi dengan IDE dengan alat refactoring pintar, yang dapat mengekstrak penutupan, mendeteksi potensi masalah, dan bahkan secara otomatis menyesuaikan kode yang diekstraksi untuk menyelesaikan masalah.
sumber
Claus Reinke: mengenai Tennent's "Desain Bahasa berdasarkan Prinsip Semantik"
Memberikan interpretasi yang menarik dari prinsip-prinsip:
"Korespondensi adalah prinsip yang memungkinkan kita mengatakan bahwa
dan
harus setara, dan bahwa apa pun yang dapat kita lakukan dalam daftar parameter formal, kita juga harus dapat melakukannya dalam deklarasi, dan sebaliknya. "[lihat juga, Reinke, di bawah.]
RD Tennent: Metode desain bahasa berdasarkan prinsip semantik
"Dua metode desain bahasa berdasarkan prinsip yang diturunkan dari pendekatan denotasional ke bahasa pemrograman semantik dijelaskan dan diilustrasikan oleh aplikasi ke bahasa Pascal. Prinsip-prinsipnya adalah, pertama, korespondensi antara parametrik dan mekanisme deklaratif, dan kedua, prinsip abstraksi untuk bahasa pemrograman yang diadaptasi dari teori himpunan. Beberapa ekstensi yang berguna dan generalisasi Pascal muncul dengan menerapkan prinsip-prinsip ini, termasuk solusi untuk masalah parameter array, dan fasilitas modularisasi. "
Claus Reinke: "Tentang pemrograman fungsional, desain bahasa, dan kegigihan" di Haskell
sumber
Untuk menjawab pertanyaan mengapa Tennent's CP sangat penting untuk desain bahasa, saya ingin mengutip Neal Gafter :
Setiap pelanggaran terhadap TCP kemungkinan akan melukai beberapa programmer di masa depan ketika ia mengharapkan penutupan bekerja seperti kode non-penutupan tetapi menemukan bahwa, dalam pelanggaran TCP, mereka tidak melakukannya.
sumber
RE Python tidak mengikuti prinsip ini. Secara umum, itu mengikuti prinsip. Contoh dasar:
Namun, Python mendefinisikan ekspresi dan pernyataan secara terpisah. Karena
if
cabang,while
loop, penugasan destruktif dan pernyataan lainnya tidak dapat digunakan dalamlambda
ekspresi sama sekali, surat prinsip Tennent tidak berlaku untuk mereka. Meski begitu, membatasi diri untuk hanya menggunakan ekspresi Python masih menghasilkan sistem lengkap Turing. Jadi saya tidak melihat ini sebagai pelanggaran terhadap prinsip; atau lebih tepatnya, jika itu melanggar prinsip, maka tidak ada bahasa yang mendefinisikan pernyataan dan ungkapan secara terpisah yang dapat sesuai dengan prinsip tersebut.Juga, jika tubuh
lambda
ekspresi menangkap jejak tumpukan, atau melakukan introspeksi lain dalam VM, itu bisa menyebabkan perbedaan. Tapi menurut saya ini seharusnya tidak dianggap sebagai pelanggaran. Jikaexpr
dan(lambda: expr)()
perlu mengkompilasi dengan bytecode yang sama, maka prinsipnya benar-benar menyangkut kompiler bukan semantik; tetapi jika mereka dapat dikompilasi ke bytecode yang berbeda, kita seharusnya tidak mengharapkan negara VM menjadi identik dalam setiap kasus.Suatu kejutan dapat ditemui menggunakan sintaksis pemahaman, meskipun saya percaya ini bukan pelanggaran prinsip Tennent juga. Contoh:
Yang mengejutkan adalah hasil dari bagaimana definisi daftar didefinisikan. Pemahaman 'kejutan' di atas setara dengan kode ini:
Dilihat dengan cara ini, pemahaman 'kejutan' di atas kurang mengejutkan, dan bukan pelanggaran prinsip Tennent.
sumber