2009-02-24 15 views
53

Jamie Zawinski usa questo termine nel suo (1997) article "java sucks" come se si dovrebbe sapere cosa significa:Cosa sono "downs funargs"?

Io odio la mancanza di verso il basso funargs; le classi anonime sono un sostituto zoppo. (Posso vivere senza chiusure longevo, ma trovo la mancanza di funzione di puntatori un dolore enorme.)

sembra essere lo slang di lisper, e ho potuto trovare il seguente breve definizione here, ma in qualche modo, penso Ancora non capisco:

Molte chiusure vengono utilizzate solo durante l'estensione delle associazioni a cui si riferiscono; questi sono noti come "downs funargs" nella parlata di Lisp.

se non fosse per Steve Yegge, mi sento stupido ora, ma sembra, potrebbe essere OK per chiedere:

Jamie Zawinski è un eroe. Una leggenda vivente. [...] Un ragazzo che può usare il termine "funarges verso il basso" e poi lanciarti un'occhiata per sfidarti a chiedergli di spiegarlo, cretino.

- XEmacs is dead, long live XEmacs

Quindi c'è un lisper qui che può compilare questo per C-style-programmatori come me?

+1

Penso che cosa significhi jwz, mentre è comprensibile che i funarg in generale non siano supportati in java, i fun-down in discesa avrebbero potuto essere supportati senza alcuna modifica al normale storage basato su stack delle variabili che sono state chiuse. La pagina di Wikipedia su "Funarg_problem" è in realtà molto chiara su questo. –

risposta

50

I fun-down verso il basso sono funzioni locali che non vengono restituite o che lasciano il loro ambito di dichiarazione. Possono essere passati solo verso il basso ad altre funzioni dall'ambito corrente.

Due esempi. Questo è un discendente funarg:

function() { 
    var a = 42; 
    var f = function() { return a + 1; } 
    foo(f); // `foo` is a function declared somewhere else. 
} 

Anche se questo non è:

function() { 
    var a = 42; 
    var f = function() { return a + 1; } 
    return f; 
} 
+0

Il primo esempio dovrebbe dire var foo = function ... –

+0

Christian: Beh, il primo implica che 'foo' è una funzione definita * ovunque *, non necessariamente localmente. Lo chiarirò. –

+7

Il punto principale è che a è in pila quando viene eseguito f, quindi non è necessario memorizzarlo da qualche altra parte (di solito insieme a f sull'heap in una cosiddetta chiusura). Quindi "downward funarg" è la parte facile di "funarg". – starblue

11

C'è un articolo abbastanza descrittiva sul Wiki chiamata Funarg problem

"A basso funarg può anche riferirsi a lo stato di una funzione quando quella funzione non è effettivamente in esecuzione. Tuttavia, perché, per definizione, l'esistenza di un funarg in giù è contenuto in l'esecuzione della funzione che lo crea , il record di attivazione per la funzione può di solito essere ancora memorizzato nello stack. "

13

In Common Lisp:

(let ((a 3)) 
    (mapcar (lambda (b) (+ a b)) 
      (list 1 2 3 4))) 

-> (4 5 6 7) 

Nella forma sopra la funzione lambda viene passato VERSO IL BASSO. Quando chiamato dalla funzione di ordine superiore MAPCAR (che ottiene una funzione e un elenco di valori come argomenti, quindi applica la funzione a ciascun elemento dell'elenco e restituisce un elenco dei risultati), la funzione lambda fa ancora riferimento alla variabile 'a' dall'espressione LET. Ma succede tutto all'interno dell'espressione LET.

Confronta sopra con questa versione:

(mapcar (let ((a 3)) 
      (lambda (b) (+ a b))) 
     (list 1 2 3 4)) 

Qui la funzione lambda viene restituita dal LET. ALTO UN PO '. Quindi viene passato al MAPCAR. Quando MAPCAR chiama la funzione lambda, il suo LET circostante non è più in esecuzione, tuttavia la funzione deve fare riferimento alla variabile 'a' dal LET.

24

Per capire meglio da dove viene il termine, è necessario conoscere un po 'di storia.

Il motivo per cui un vecchio hacker di Lisp potrebbe distinguere ribasso funargs da funargs in generale è che funargs ribasso sono facili da implementare in un Lisp tradizionale che manca variabili lessicali, mentre il caso generale è difficile.

Tradizionalmente una variabile locale è stato attuato in un interprete Lisp con l'aggiunta di un vincolante (il nome del simbolo della variabile, in coppia con il suo valore) per l'ambiente . Un tale ambiente era semplice da implementare usando un elenco di associazioni. Ogni funzione aveva il proprio ambiente e un puntatore all'ambiente della funzione genitore. Un riferimento di variabile è stato risolto cercando nell'ambiente corrente e, se non trovato, nell'ambiente padre e così via nella pila di ambienti fino a quando non è stato raggiunto l'ambiente globale.

In tale implementazione, variabili locali shadow variabili globali con lo stesso nome. Ad esempio, in Emacs Lisp, print-length è una variabile globale che specifica la lunghezza massima dell'elenco da stampare prima di abbreviarlo. Legandosi questa variabile attorno alla chiamata a una funzione è possibile modificare il comportamento di istruzioni di stampa all'interno di tale funzione:

 
(defun foo() (print '(1 2 3 4 5 6))) ; output depends on the value of print-length 

(foo) ; use global value of print-length 
    ==> (1 2 3 4 5 6) 

(let ((print-length 3)) (foo)) ; bind print-length locally around the call to foo. 
    ==> (1 2 3 ...) 

Si può vedere che in una tale realizzazione, ribasso funargs sono davvero facili da implementare, perché le variabili che si trovano nell'ambiente della funzione quando viene creata sarà ancora nell'ambiente della funzione quando viene valutata.

variabili che agiscono come questo sono chiamati speciali o dinamici variabili, ed è possibile creare in Common Lisp utilizzando la dichiarazione special.