Qual è la buona spiegazione del principio di corrispondenza di Tennent?


21

Mi sono trovato in difficoltà nel vedere di cosa tratta questo principio e perché è così importante per la progettazione del linguaggio.

Fondamentalmente, afferma, che per ogni espressione exprnel linguaggio dovrebbe essere esattamente la stessa di questo costrutto:

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

Inoltre, ho sentito che Ruby obbedisce a questo principio, mentre Python no. Non capisco perché sia ​​vero o se sia vero.


3
Non riesco a capire perché sia ​​fuori tema, qualcuno potrebbe spiegarmelo?
Andrew,

3
Ci sono un paio di problemi; L'ho ritoccato e lo sto inviando ai programmatori, dove discussioni come questa sono un po 'più gradite.
Strappato il

1
Ruby non obbedisce a questo principio: supponiamo di exprottenere la traccia dello stack corrente.
Landei,

Risposte:


18

Non ho mai sentito parlare del "Principio di corrispondenza di Tennent" e ancor meno di essere importante nella progettazione del linguaggio. Cercare su Google le espressioni sembra tutto portare a un blog di Neal Gafter del 2006 che stabilisce ciò che pensa che sia e come pensa che dovrebbe applicarsi anche alle chiusure. E la maggior parte degli altri nei forum sembra riferirsi alla voce di Gafter.

Ecco comunque una menzione di detto "TCP" di Douglas Crockford (un nome che conosco e di cui mi fido): http://java.sys-con.com/node/793338/ . In parte

Ci sono alcune cose che non possono essere racchiuse in quel modo, come dichiarazioni di ritorno e dichiarazioni di rottura, che i sostenitori del Principio di corrispondenza (o TCP) di Tennent sostengono sia un sintomo di un cattivo odore. Yow! Il design del linguaggio è già abbastanza difficile senza dover far fronte alle allucinazioni olfattive. Per capire meglio il problema, ho comprato una copia del libro di Tennent del 1981, Principles of Programming Languages.

Si scopre che il Principio di corrispondenza è descrittivo , non prescrittivo . Lo usa per analizzare il linguaggio di programmazione Pascal (ormai dimenticato), mostrando una corrispondenza tra definizioni variabili e parametri di procedura. Tennent non identifica la mancanza di corrispondenza delle dichiarazioni di reso come un problema .

Quindi sembra quindi che il nome "Principio di corrispondenza di Tennent" sia usato in modo improprio, e qualunque cosa Neal parli probabilmente dovrebbe essere chiamata "TCP immaginato e possibilmente generalizzato di Gafter" ... o qualcosa del genere. In ogni caso, non basta nascondersi dietro un sipario del libro fuori stampa


1
+1 per "TCP immaginato e possibilmente generalizzato di
Gafter

9

Vedo questo come parte di una regola generale secondo cui un linguaggio ben progettato fa ciò che un programmatore si aspetterebbe naturalmente. Se ho un blocco di codice che voglio refactificare in una chiusura e avvolgo quel blocco con la sintassi appropriata senza pensare davvero alle singole linee di codice, allora mi aspetto che quel blocco faccia la stessa cosa nella chiusura come fatto in linea. Se alcune istruzioni usano la parola chiave "this" (forse implicitamente) e il linguaggio fa "this" utilizzato all'interno della chiusura si riferisce a una classe anonima utilizzata per rappresentarla anziché alla classe che definisce il metodo che definisce la chiusura, quindi il significato di quelle dichiarazioni sono cambiate, il mio blocco di codice non fa più quello che penso faccia e devo rintracciare un bug e capire come cambiare il mio codice per funzionare nella chiusura.

Il problema potrebbe anche essere mitigato con un IDE con strumenti di refactoring intelligenti, in grado di estrarre chiusure, rilevare potenziali problemi e persino regolare automaticamente il codice estratto per risolverli.


3

Claus Reinke: riguardo al "Language Design basato su principi semantici" di Tennent offre
un'interpretazione interessante dei principi:
"La corrispondenza è il principio che ci permette di dire che

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

e

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

dovrebbe essere equivalente e qualsiasi cosa possiamo fare negli elenchi di parametri formali, dovremmo anche essere in grado di fare nelle dichiarazioni e viceversa. "[vedi anche Reinke, di seguito.]

RD Tennent: Metodi di progettazione del linguaggio basati su principi semantici
"Due metodi di progettazione del linguaggio basati su principi derivati ​​dall'approccio denotazionale alla programmazione della semantica del linguaggio sono descritti e illustrati da un'applicazione al linguaggio Pascal. I principi sono, in primo luogo, la corrispondenza tra parametrico e meccanismi dichiarativi, e in secondo luogo, un principio di astrazione per linguaggi di programmazione adattati dalla teoria degli insiemi. Numerose estensioni e generalizzazioni utili di Pascal emergono applicando questi principi, inclusa una soluzione al problema dei parametri dell'array e una struttura di modularizzazione ".

Claus Reinke: "Sulla programmazione funzionale, la progettazione del linguaggio e la persistenza" su Haskell


Claus Reinke: "Programmazione funzionale, design del linguaggio e persistenza" su Haskell su community.haskell.org/~claus/publications/fpldp.html
Kris,

2

Per rispondere alla domanda sul perché il CP di Tennent è così importante per la progettazione del linguaggio, vorrei citare Neal Gafter :

I principi di Tennent sono molto potenti perché le violazioni di essi tendono a manifestarsi nella lingua come difetti, irregolarità, restrizioni inutili, interazioni o complicazioni impreviste e così via.

Qualsiasi violazione di TCP rischia di danneggiare alcuni programmatori in futuro quando si aspetta che le chiusure funzionino come un codice di non chiusura, ma scopre che, in violazione di TCP, non lo fanno.


1

RE Python non segue questo principio. In generale, segue il principio. Esempio di base:

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

Tuttavia, Python definisce le espressioni e le dichiarazioni separatamente. Poiché i iframi, i whilecicli, i compiti distruttivi e le altre dichiarazioni non possono essere affatto utilizzati nelle lambdaespressioni, la lettera del principio di Tennent non si applica a loro. Anche così, limitarsi a usare solo espressioni Python produce ancora un sistema completo di Turing. Quindi non vedo questo come una violazione del principio; o meglio, se viola il principio, allora nessun linguaggio che definisce le dichiarazioni e le espressioni separatamente può eventualmente conformarsi al principio.

Inoltre, se il corpo lambdadell'espressione stava acquisendo una traccia dello stack o eseguiva altre introspezioni nella VM, ciò potrebbe causare differenze. Ma secondo me questo non dovrebbe essere considerato una violazione. Se expre (lambda: expr)() necessariamente compilare con lo stesso bytecode, allora il principio riguarda davvero i compilatori e non la semantica; ma se possono compilare in bytecode diverso, non dovremmo aspettarci che lo stato della VM sia identico in ogni caso.

Una sorpresa può essere riscontrata usando la sintassi della comprensione, anche se credo che questa non sia una violazione del principio di Tennent. Esempio:

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

La sorpresa è il risultato di come sono definite le comprensioni dell'elenco. La comprensione "sorpresa" sopra è equivalente a questo codice:

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

Vista in questo modo, la comprensione della "sorpresa" sopra è meno sorprendente, e non una violazione del principio di Tennent.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.