Qual è la base matematica per i valori di prima / seconda / terza classe nei linguaggi di programmazione?


19

aggiunto

Ho appena trovato due domande correlate

/math//q/1759680/1281

/programming//a/2582804/156458


Nei linguaggi di programmazione, dalla programmazione del linguaggio pragmatico di Michael Scott

In generale, si dice che un valore in un linguaggio di programmazione abbia uno stato di prima classe se può essere passato come parametro, restituito da una subroutine o assegnato in una variabile. I tipi semplici come numeri interi e caratteri sono valori di prima classe nella maggior parte dei linguaggi di programmazione. Al contrario, un valore di "seconda classe" può essere passato come parametro, ma non restituito da una subroutine o assegnato in una variabile e un valore di "terza classe" non può nemmeno essere passato come parametro.

Le etichette sono valori di terza classe nella maggior parte dei linguaggi di programmazione, ma valori di seconda classe in Algol. Le subroutine mostrano la maggior parte delle variazioni. Sono valori di prima classe in tutti i linguaggi di programmazione funzionali e nella maggior parte dei linguaggi di scripting. Sono anche valori di prima classe in C # e, con alcune restrizioni, in molti altri linguaggi imperativi, tra cui Fortran, Modula-2 e -3, Ada 95, C e C ++. 11 Sono valori di seconda classe nella maggior parte delle altre lingue imperative e valori di terza classe in Ada 83.

  1. Qual è la base matematica per i valori di prima / seconda / terza classe nei linguaggi di programmazione?

    La terminologia mi ricorda la logica del primo / secondo ordine, ma sono correlati?

  2. Mi sembra che la differenza tra loro sia il caso specifico in cui un valore può essere utilizzato

    • passato come parametro,
    • restituito da una subroutine, oppure
    • assegnato in una variabile.

    Perché i casi specifici sono importanti, mentre non altri casi non menzionati?

Grazie.


23
Classificare i valori in prima / seconda classe è inutile quanto classificare le lingue in paradigmi. Tutto ciò con cui finirai sono vaghe generalizzazioni che confondono il quadro. Questo non è l'approccio giusto per comprendere i linguaggi di programmazione. L'importante è capire la sintassi, la statica e la dinamica del linguaggio, ma è troppo grande per essere inserito in un commento
gardenhead,

3
A parte: PL / I sarebbe un esempio di etichette di prima classe. In PL / I puoi dichiarare le variabili digitate sull'etichetta, assegnare loro posizioni di codice e andare a loro. Puoi anche passarli come parametri e persino crearne array.
Theraot,

@Theraot: Forse sto uscendo con me stesso, ma sono l'unico che abbia mai avuto a che fare con GOTO assegnati e calcolati in FORTRAN? E no, non ho scritto @ $%! codice, ero bloccato a riprogettarlo.
jamesqf,

@jamesqf Sono a conoscenza dell'assegnazione alle etichette in FORTRAN e COBOL, no, non l'ho usato. Non sono sicuro di come classificare le etichette lì. Eppure per quello che leggo (ho i manuali) PL / I va oltre, e sono convinto che le etichette siano di prima classe lì.
Theraot,

Risposte:


45

Non ce n'è, ed è piuttosto arbitrario.

L'unica utile distinzione è tra la prima classe e tutte le altre. Ogni caso che si trova nella "altra" parentesi ha una propria serie distinta di regole in ciascun caso e raggrupparli tutti insieme non è molto utile. "Prima classe" significa "Non devi cercare le regole", in sostanza, e "altro" è "Devi imparare le regole".

Ad esempio, in C ++ le singole funzioni sono valori di prima classe, purché siano apolidi. I set di sovraccarico non sono, ma lo sono i lambda. In C # le funzioni sono generalmente valori di prima classe ma ci sono alcuni casi imbarazzanti che sorgono quando si tratta di inferenza di tipo che impedisce loro di essere in tutti i casi.


10
+1, anche se nel contesto di un libro come la programmazione della pragmatica del linguaggio che confronta un gran numero di costrutti in un gran numero di lingue e analizza le somiglianze, le differenze e le implicazioni in profondità, penso che questo tipo di stenografia possa essere utile. (Basta non andare in giro aspettandosi che le altre persone capiscano "di seconda mano" e "di seconda mano" come significanti cose specifiche.)
ruakh

(Uh, dove per "seconda mano" e "seconda mano" intendo ovviamente "seconda classe" e "terza classe". :-P)
ruakh,

3
Se vuoi commerciare con funzioni di seconda mano, è meglio farlo in una lingua in cui le funzioni sono cittadini di prima classe. ^^
5gon12eder

@ 5gon12eder: "funzioni di seconda mano" sarebbero quelle che chiami dalle librerie di terze parti, no?
jamesqf,

11

Concordo con DeadMG, l'importante distinzione è tra prima classe e "tutto il resto". Tuttavia, esiste un modo più familiare per classificare la differenza.

I valori di prima classe sono dati, gli altri sono codice. (in parole povere: sono sicuro che ci sono delle eccezioni. Ma questa è una buona approssimazione valida per le lingue del mondo reale.)

In alcune lingue è possibile trattare il codice come dati. I linguaggi funzionali sono famosi per questo: alcuni di essi consentono di modificare il codice del programma mentre è in esecuzione (il fondamento della programmazione genetica ).

Linguaggi come C e C ++ ti consentono di prendere l'indirizzo delle funzioni: mentre non puoi modificarle, puoi passare funzioni come parametri ad altre funzioni. Il C ++ ha anche lo zucchero sintattico dei funzioni . L'idea è quella di creare un intero oggetto che, in superficie, sembra comportarsi come una funzione e può essere passato come se fosse un dato. Ciò che è altrimenti una classe di valore inferiore può essere trattato come un valore di prima classe.

Matematicamente, penso che il modo migliore è quello di pensare di un programma di AST . In genere, ogni token ha un tipo specifico che può essere o non essere compatibile con altri tipi. Pensa a l-value, r-value e all'altro intero casino di tipi di valore in C ++ . Quindi aggiungi le parole chiave, i simboli che sono funzioni, ecc. Alcuni di questi possono essere valori di prima, seconda o terza classe a seconda della lingua.

Non sono sicuro che conoscere la "classe" di valore sia così importante, tranne forse in un ambiente accademico. Nel mondo reale, la cosa importante da sapere è come è possibile passare il codice, trattandolo come un dato: funzione, funzione / chiusura, puntatore a funzione, ecc.


2
Un esempio di un valore non di prima classe non di codice: Lua ha una speciale ..."variabile" utilizzata per indicare i parametri della funzione vararg. Puoi usarlo in molte espressioni come se fosse un elenco di valori (come print(...)o local args = {...}) ma ci sono alcune cose che non puoi fare con esso, come fare riferimento ad esso in una chiusura ( function(...) return function() return ... end end).
Colonnello trentadue

8

La semantica denotazionale fornisce una base matematica per descrivere come funzionano valori e variabili in un linguaggio di programmazione. È stato spiegato così bene nel mio corso di laurea in Informatica che ho ottenuto il massimo dei voti nell'esame di semantica denotazionale, poi ho dimenticato la maggior parte di esso e non ho mai avuto bisogno di usarlo in una vita di 20 anni come programmatore.

Puoi scegliere di usare una base matematica ben definita, oppure puoi usare una terminologia informale come "stato di prima classe". Avrei imparato molto di più se il corso fosse basato sulla Pragmatica del linguaggio di programmazione di Scott, tuttavia la matematica formale è necessaria per qualcuno che sta per fare un dottorato di ricerca in progettazione del linguaggio di programmazione.

Se leggi le specifiche per la maggior parte dei linguaggi di programmazione, noterai una mancanza dissidente di semantica denotazionale, tuttavia la maggior parte dei linguaggi ben progettati aveva nel team qualcuno che è esperto nella progettazione del linguaggio di programmazione, quindi capisce bene la semantica denotazionale.

Quindi Michearl Scott usa una terminologia informale che ha qualche relazione con la matematica formale, mentre presenta l'argomento in modo che la maggior parte dei programmatori possa beneficiare. La sua terminologia non è utilizzata da altre persone, quindi non è utile per comunicare, ma ti dà una buona base sulle domande che dovresti porre quando vedi un nuovo linguaggio di programmazione per la prima volta.

Si noti che Michael L. Scott è un ricercatore di spicco nel campo dell'Informatica, quindi capirà e sarà molto contento di usare la matematica formale, ma come i migliori ricercatori è abile nello spiegare l'applicazione della ricerca a tutti noi.


Grazie. Quali libri sono stati usati nella tua classe? Quali libri mi consigliate ora? Sono un autodidatta
Tim

@Tim, ho fatto la mia lezione oltre 20 anni fa! Mi aspetto che il libro di Michearl Scott sia uno dei migliori e coprirà più del necessario a meno che tu non abbia intenzione di fare ricerche a livello di dottorato.
Ian,

3

No, la parola "primo" in "prima classe" e in "primo ordine" significa cose diverse.

Ma sì, i concetti di "prima classe" e "primo ordine" sono correlati. Si tratta entrambi di classificare quali concetti su cui una lingua può descrivere la lingua può anche astrarre.

Un concetto è di prima classe se i soliti meccanismi di astrazione di una lingua possono astrarre su quel concetto.

Ad esempio, il linguaggio di programmazione Java può descrivere numeri interi e tutti i soliti meccanismi per astrarre su numeri interi (accettandoli come parametri di metodo, restituendoli come risultati di funzioni, memorizzandoli in strutture di dati, ...) funzionano per numeri interi.

Un concetto è di primo ordine se non può essere usato per astrarre su se stesso.

Ad esempio, sempre in Java, possiamo usare metodi per astrarre certe cose. Ma non possiamo usare i metodi per astrarre sui metodi, perché un nome di metodo non può essere passato come parametro di metodo. Questo è diverso in JavaScript, dove puoi usare la notazione parentesi per accedere a una proprietà di un oggetto con il suo nome come stringa e puoi astrarre su stringhe.

Un concetto è di secondo ordine se può essere usato per astrarre su usi di primo ordine di se stesso, ma non su usi di secondo ordine.

Ad esempio, in Java, è possibile utilizzare Generics per astrarre i tipi (come in class Foo<T> { public List<T> content; }). Tuttavia, non è possibile utilizzare i generici per astrarre sui generici (come in class Bar<T> { public T<Int> content; }). Questo è diverso in Scala.

Un concetto è di terzo ordine se può essere usato per astrarre su usi di primo e secondo ordine di se stesso, ma non su usi di secondo ordine.

E così via.

Infine, un concetto è di ordine superiore se può essere utilizzato per astrarre su usi arbitrari di se stesso.

Riepilogo: se una funzione di astrazione è di prima classe, è anche di ordine superiore. E se una funzione di astrazione è di primo ordine, non può essere di prima classe.


1
È possibile fare List<List>in Java, però. Forse puoi chiarire cosa intendi con quella parte?
Poligome,

1
Buon punto. Voglio dire: class Foo<A> { A<Int> ... }. Cioè, intendo usare un parametro di tipo generico come classe generica. Quindi, Foo<List>sarebbe un'istanza A<Int>per List<Int>. In Java, ciò non è possibile. Proverò a modificarlo nella risposta più tardi.
Toxaris,

In effetti, questo non è possibile.
Polygnome,

Ora ho sostituito l' List<List>esempio fuorviante . Grazie per aver segnalato il problema, @Polygnome.
Toxaris,

@Toxaris Penso che questa sia solo una terminologia idiosincratica che ti sei inventato. Un "concetto" non è di primo o secondo ordine, è un quantificatore logico.
Miles Rout,

2

Qual è la base matematica per i valori di prima / seconda / terza classe nei linguaggi di programmazione?

Nessuno di cui sono a conoscenza.

La terminologia mi ricorda la logica del primo / secondo ordine, ma sono correlati?

Non proprio.

La "classe" di un elemento del linguaggio di programmazione è solo un modo abbreviato di pensare alla domanda quali cose l'utente del mio linguaggio desidera manipolare a livello di programmazione ? Ad esempio, C # offre un ricco set di operazioni per manipolare i valori , un set meno ricco di modi per manipolare i tipi e nessuna operazione che manipola le etichette .

Tuttavia, l'intuizione che esiste una connessione qui non è del tutto fuori luogo. Esiste un'analogia dalla logica del primo ordine alla programmazione procedurale e dalla logica di ordine superiore alla programmazione funzionale. La logica del primo ordine riguarda la manipolazione logica dei valori; la programmazione procedurale riguarda la manipolazione programmatica dei valori. La logica di ordine superiore riguarda la manipolazione logica delle affermazioni della logica , la programmazione funzionale riguarda la manipolazione programmatica delle funzioni .

Perché i casi specifici sono importanti, mentre non altri casi non menzionati?

Dovresti chiedere all'autore una risposta definitiva.

Non sarei troppo impiccato su questa nozione di "classe". Non è una cosa formalmente definita. È una scorciatoia che i designer linguistici usano per parlare di quali cose possono essere manipolate a livello di programmazione.


2

"Valore di prima classe", in questo contesto, è una terminologia standard nella teoria del linguaggio di programmazione. Un valore di prima classe è qualcosa che può essere manipolato come valori normali nella lingua, qualcosa che può essere calcolato in fase di esecuzione. Naturalmente, questa è una definizione tautologica fino a quando non hai definito una semantica per la lingua, e quindi un valore è qualunque cosa la semantica definisca un valore. Il punto del concetto è identificare ciò che può essere manipolato direttamente, invece di accedervi solo indirettamente.

Ad esempio, in quasi tutti i linguaggi di programmazione, numeri interi di macchine di dimensioni limitate (ad esempio numeri interi a 8 bit, numeri interi a 32 bit o numeri interi a 64 bit, ecc.) Sono valori di prima classe. Puoi memorizzarli in variabili, passarli e restituirli a funzioni, ecc. Nella maggior parte delle lingue ma non linguaggi di basso livello come assembly e C, le stringhe sono valori di prima classe - ma in C non lo sono, tu solo ottenere puntatori alle stringhe. In C, stringhe e array non sono valori di prima classe: ad esempio non è possibile passare un array a una funzione, non è possibile assegnare un array a una variabile di array, ecc. In C, le funzioni non sono valori di prima classe O: non è possibile memorizzare una funzione in una variabile, solo un puntatore a una funzione. Al contrario, le stringhe e le funzioni sono valori di prima classe nella maggior parte dei linguaggi di programmazione di alto livello: è possibile memorizzarli in una stringa, ecc.

Un esempio di un concetto che non è di prima classe in molti linguaggi di programmazione progettati per essere compilati sono i tipi. In un linguaggio come C o Java, i tipi vivono al momento della compilazione, non è possibile manipolarli usando costrutti di linguaggio. (Java ha anche un sistema di tipi dinamico basato sulle classi; le classi sono valori di prima classe attraverso la riflessione.) Al contrario, un linguaggio come Python ha una typefunzione che restituisce un valore che rappresenta il tipo del suo argomento.

La negazione del "valore di prima classe" nella terminologia standard non è "un valore di prima classe". Il termine "valore di seconda classe" non è comunemente usato e "valore di terza classe" ancora meno. Non aspettarti di vederli al di fuori di questo libro. Non c'è assolutamente alcuna base per definire "secondo" in quanto "può essere passato come parametro" e "terzo" come "non può essere passato come parametro", non esiste una scala di cose che potrebbero essere numerate in modo significativo. Pochissime lingue fanno la differenza tra valori che possono essere passati come parametro a funzioni e valori che possono essere assegnati a variabili, quindi non è utile definire un nome per questo concetto.

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.