Domanda

Lo schema utilizza un singolo spazio dei nomi per tutte le variabili, indipendentemente dal fatto che siano associate a funzioni o altri tipi di valori. Common Lisp separa i due, in modo tale che l'identificatore "ciao" può fare riferimento a una funzione in un contesto e una stringa in un altro.

(Nota 1: questa domanda ha bisogno di un esempio di quanto sopra; sentiti libero di modificarlo e aggiungerne uno, o inviare un'e-mail all'autore originale e lo farò.)

Tuttavia, in alcuni contesti, come passare funzioni come parametri ad altre funzioni, il programmatore deve distinguere esplicitamente che sta specificando una variabile di funzione, piuttosto che una variabile non di funzione, usando # ' , come in:

(sort (list '(9 A) '(3 B) '(4 C)) #'< :key #'first)

L'ho sempre considerato un po 'una verruca, ma di recente mi sono imbattuto in un argomento che questa è in realtà una caratteristica:

...il un'importante distinzione sta proprio nella sintassi delle forme, non nella tipo di oggetti. Senza sapere nulla dei valori di runtime coinvolto, è abbastanza chiaro che il primo elemento di una forma di funzione deve essere una funzione. CL prende questo fatto e lo rende parte del linguaggio, insieme a macro e forme speciali che possono anche (e devono) essere determinato staticamente. Quindi la mia domanda è: perché dovresti volerlo i nomi delle funzioni e i nomi delle variabili devono essere nella stessa spazio dei nomi, quando l'uso principale dei nomi delle funzioni deve apparire dove a il nome della variabile raramente vorrebbe apparire?
Considera il caso dei nomi delle classi: perché una classe chiamata FOO dovrebbe prevenirla l'uso di variabili denominate FOO? L'unica volta che mi riferivo al la classe con il nome FOO è in contesti che prevedono un nome di classe. Se acceso la rara occasione in cui ho bisogno di ottenere l'oggetto di classe che è legato al nome classe FOO, c'è FIND-CLASS.

Questo argomento ha un senso per me dall'esperienza; esiste un caso simile in Haskell con i nomi dei campi, che sono anche funzioni utilizzate per accedere ai campi. Questo è un po 'imbarazzante:

data Point = Point { x, y :: Double {- lots of other fields as well --} }
isOrigin p = (x p == 0) && (y p == 0)

Questo è risolto da un po 'di sintassi extra, resa particolarmente piacevole dall'estensione NamedFieldPuns :

isOrigin2 Point{x,y} = (x == 0) && (y == 0)

Quindi, alla domanda, oltre la coerenza, quali sono i vantaggi e gli svantaggi, sia per Common Lisp vs. Scheme che in generale, di un singolo spazio dei nomi per tutti i valori rispetto a quelli separati per funzioni e valori non funzionali?

È stato utile?

Soluzione

I due diversi approcci hanno nomi: Lisp-1 e Lisp-2. Un Lisp-1 ha un singolo spazio dei nomi per variabili e funzioni (come nello schema) mentre un Lisp-2 ha spazi dei nomi separati per variabili e funzioni (come in Common Lisp). Lo dico perché potresti non essere a conoscenza della terminologia poiché non ti sei fatto riferimento nella tua domanda.

Wikipedia si riferisce a questo dibattito :

  

Se uno spazio dei nomi separato per le funzioni sia un vantaggio è una fonte di contesa nella comunità Lisp. Di solito viene chiamato dibattito Lisp-1 vs. Lisp-2. Lisp-1 si riferisce al modello di Schema e Lisp-2 si riferisce al modello di Common Lisp. Questi nomi sono stati coniati in un articolo del 1988 di Richard P. Gabriel e Kent Pitman, che confronta ampiamente i due approcci.

L'articolo di Gabriel e Pitman intitolato Problemi tecnici di separazione in celle di funzioni e celle di valore risolve proprio questo problema.

Altri suggerimenti

In realtà, come indicato nel l'articolo di Richard Gabriel e Kent Pitman , il dibattito riguarda Lisp-5 contro Lisp-6, poiché ci sono già molti altri spazi dei nomi lì, nel documento sono menzionati nomi di tipi, nomi di tag, nomi di blocchi e nomi di dichiarazioni. modifica: questo sembra essere errato, come sottolinea Rainer nel commento: Lo schema in realtà sembra essere un Lisp-1. Tuttavia, quanto segue non è in gran parte interessato da questo errore.

Se un simbolo indica qualcosa da eseguire o qualcosa a cui fare riferimento è sempre chiaro dal contesto. Lanciare funzioni e variabili nello stesso spazio dei nomi è principalmente una restrizione: il programmatore non può usare lo stesso nome per una cosa e un'azione. Ciò che un Lisp-5 ottiene da questo è solo che viene evitato un sovraccarico sintattico per fare riferimento a qualcosa di uno spazio dei nomi diverso da quello che implica il contesto attuale. modifica: questa non è l'intera immagine, solo la superficie.

So che ai sostenitori di Lisp-5 piace il fatto che le funzioni siano dati e che questo sia espresso nel nucleo del linguaggio. Mi piace il fatto di poter chiamare un elenco " list " e un'auto "auto" senza confondere il mio compilatore, e le funzioni sono comunque un tipo di dati fondamentalmente speciali. modifica: questo è il mio punto principale: spazi dei nomi separati non sono affatto una verruca.

Mi è piaciuto anche ciò che Pascal Constanza doveva dì su questo.

Ho incontrato una distinzione simile in Python (spazio dei nomi unificato) vs Ruby (spazi dei nomi distinti per metodi vs non metodi). In quel contesto, preferisco l'approccio di Python - per esempio, con quell'approccio, se voglio fare un elenco di cose, alcune delle quali sono funzioni mentre altre no, non devo fare nulla di diverso con i loro nomi , a seconda della loro "funzionalità", ad esempio. Considerazioni simili si applicano a tutti i casi in cui gli oggetti funzione devono essere banditi piuttosto che richiamati (argomenti a, e restituire valori da, funzioni di ordine superiore, ecc, ecc.)

Anche le non funzioni possono essere chiamate (se le loro classi definiscono __call__ , nel caso di Python - un caso speciale di "sovraccarico dell'operatore"), quindi la "distinzione contestuale" neanche necessariamente chiaro.

Tuttavia, il mio "lisp-oid" l'esperienza è / era principalmente con Schema piuttosto che Common Lisp, quindi potrei essere inconsciamente influenzato dalla familiarità con lo spazio dei nomi uniforme che alla fine proviene da quell'esperienza.

Il nome di una funzione in Scheme è solo una variabile con la funzione come valore. Sia che io faccia (definisco x (y) (zy)) o (let ((x (lambda (y) (zy)))) , sto definendo un funzione che posso chiamare. Quindi l'idea che "un nome di variabile raramente vorrebbe apparire lì" è piuttosto speciosa per quanto riguarda Scheme.

Lo schema è un linguaggio caratteristicamente funzionale, quindi trattare le funzioni come dati è uno dei suoi principi. Fare in modo che le funzioni siano un tipo memorizzato come tutti gli altri dati è un modo per portare avanti l'idea.

Il lato negativo più grande che vedo, almeno per Common Lisp, è la comprensibilità. Siamo tutti d'accordo sul fatto che utilizza spazi dei nomi diversi per variabili e funzioni, ma quanti ne ha? In PAIP, Norvig ha dimostrato di avere almeno "sette" namespace.

Quando uno dei libri classici della lingua, scritto da un programmatore molto rispettato, non può nemmeno dirlo con certezza in un libro pubblicato, penso che ci sia un problema. Non ho problemi con più spazi dei nomi, ma vorrei che la lingua fosse, almeno, abbastanza semplice da consentire a qualcuno di comprenderne interamente questo aspetto.

Mi sento a mio agio a usare lo stesso simbolo per una variabile e per una funzione, ma nelle aree più oscure ricorro all'uso di nomi diversi per paura (scontrarsi con gli spazi dei nomi può essere davvero difficile da eseguire il debug!), e questo dovrebbe davvero non essere mai il caso.

Ci sono cose buone in entrambi gli approcci. Tuttavia, trovo che quando è importante, preferisco avere sia una LISTA di funzioni che una LISTA variabile piuttosto che doverne sillabarne una in modo errato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top