Trudno mi było zrozumieć, na czym polega ta zasada i dlaczego jest tak ważna w projektowaniu języka.
Zasadniczo stwierdza, że każde wyrażenie expr
w języku powinno być dokładnie takie samo jak ten konstrukt:
(function () { return expr; })()
Słyszałem też, że Ruby przestrzega tej zasady, podczas gdy Python nie. Nie rozumiem, dlaczego to prawda, czy w ogóle to prawda.
design
language-agnostic
Andrzej
źródło
źródło
expr
pobiera bieżący ślad stosu.Odpowiedzi:
Nigdy wcześniej nie słyszałem o „zasadzie korespondencji Tennenta”, a tym bardziej o jej znaczeniu w projektowaniu języka. Wydaje się, że przeglądanie tych wyrażeń prowadzi do jednego bloga Neal Gafter z 2006 roku, który określa, co on uważa za to i jak według niego powinno to dotyczyć również zamknięć. I większość innych na forach wydaje się odnosić do wpisu Gaftera.
Oto jednak wzmianka o „TCP” Douglasa Crockforda (nazwisko, które znam i któremu ufam): http://java.sys-con.com/node/793338/ . Częściowo
Wydaje się więc, że nazwa „Zasada Korespondencji Tennenta” jest niewłaściwie używana, a wszystko, o czym mówi Neal, powinno być nazywane „Wyobrażonym i możliwym uogólnionym TCP Gaftera”… lub coś w tym rodzaju. W każdym razie nie wystarczy, aby schować się za zasłoną z wyczerpanego nakładu na książkę
źródło
Widzę to jako część ogólnej zasady, że dobrze zaprojektowany język robi to, czego programista naturalnie oczekiwałby. Jeśli mam blok kodu, który chcę przekształcić w zamknięcie, i zawijam ten blok za pomocą odpowiedniej składni, nie myśląc o poszczególnych wierszach kodu, to oczekuję, że blok ten zrobi to samo w zamknięciu, ponieważ zrobił inline. Jeśli niektóre instrukcje używają słowa kluczowego „to” (być może niejawnie), a język sprawia, że „to” użyte w zamknięciu odnosi się do anonimowej klasy użytej do jego reprezentacji, a nie do klasy, która definiuje metodę definiującą zamknięcie, wówczas znaczenie te instrukcje się zmieniły, mój blok kodu nie robi już tego, co myślę, i muszę wyśledzić błąd i dowiedzieć się, jak zmienić kod, aby działał w zamknięciu.
Problem można również złagodzić za pomocą IDE z inteligentnymi narzędziami do refaktoryzacji, które mogą wyodrębniać zamknięcia, wykrywać potencjalne problemy, a nawet automatycznie dostosowywać wyodrębniony kod w celu rozwiązania problemów.
źródło
Claus Reinke: w sprawie „Projektu języka opartego na zasadach semantycznych”
Tennenta przedstawia interesującą interpretację zasad:
„Korespondencja to zasada, która pozwala nam powiedzieć, że
i
powinny być równoważne i że wszystko, co możemy zrobić na formalnych listach parametrów, powinniśmy również móc to zrobić w deklaracjach i odwrotnie. ”[patrz także Reinke poniżej].
RD Tennent: Metody projektowania języka oparte na zasadach semantycznych
„Dwie metody projektowania języka oparte na zasadach wywodzących się z denotacyjnego podejścia do programowania semantyki języka programowania są opisane i zilustrowane przez aplikację do języka Pascal. Zasady są, po pierwsze, zgodnością między parametrycznym a mechanizmy deklaratywne, a po drugie zasada abstrakcji dla języków programowania dostosowana do teorii mnogości. Pojawia się kilka użytecznych rozszerzeń i uogólnień Pascala poprzez zastosowanie tych zasad, w tym rozwiązanie problemu z parametrem macierzy oraz możliwość modularyzacji ”.
Claus Reinke: „O programowaniu funkcjonalnym, projektowaniu języka i wytrwałości” w Haskell
źródło
Aby odpowiedzieć na pytanie, dlaczego CP Tennent jest tak ważny dla projektowania języka, chciałbym zacytować Neala Gaftera :
Każde naruszenie TCP może w przyszłości zaszkodzić programiście, gdy spodziewa się, że zamknięcia będą działać jak kod nie-zamknięty, ale stwierdzi, że tak nie jest.
źródło
RE Python nie przestrzega tej zasady. Ogólnie rzecz biorąc, działa zgodnie z zasadą. Podstawowy przykład:
Jednak Python definiuje wyrażenia i instrukcje osobno. Ponieważ
if
rozgałęzień,while
pętli, destrukcyjnego przypisania i innych instrukcji nie można w ogóle używać wlambda
wyrażeniach, litera zasady Tennent nie ma do nich zastosowania. Mimo to ograniczenie się do używania tylko wyrażeń w języku Python nadal powoduje utworzenie pełnego systemu Turinga. Dlatego nie uważam tego za naruszenie zasady; a raczej, jeśli narusza zasadę, żaden język, który definiuje oświadczenia i wyrażenia osobno, nie może być zgodny z tą zasadą.Ponadto, jeśli treść
lambda
wyrażenia przechwytuje ślad stosu lub wykonuje inne introspekcje w maszynie wirtualnej, może to powodować różnice. Ale moim zdaniem nie powinno to być traktowane jako naruszenie. Jeśliexpr
i(lambda: expr)()
koniecznie kompiluje się do tego samego kodu bajtowego, wówczas zasada naprawdę dotyczy kompilatorów, a nie semantyki; ale jeśli można je skompilować do innego kodu bajtowego, nie należy oczekiwać, że stan maszyny wirtualnej będzie identyczny w każdym przypadku.Przy użyciu składni rozumowania można spotkać niespodziankę, chociaż uważam, że nie jest to również naruszenie zasady Tennent. Przykład:
Zaskoczenie wynika z tego, jak definiowane są wyrażenia listowe. Powyższe rozumienie „niespodzianki” jest równoważne z tym kodem:
Patrząc w ten sposób powyższe rozumienie „niespodzianki” jest mniej zaskakujące i nie stanowi naruszenia zasady Tennent.
źródło