2009-02-24 4 views
53

Jamie Zawinski utilise ce terme dans son (1997) article "java sucks" comme si vous devez savoir ce que cela signifie:Que sont les "downargs"?

Je déteste vraiment le manque de baisse-funargs; les classes anonymes sont un substitut boiteux. (Je peux vivre sans fermeture longue durée de vie, mais je trouve le manque de pointeurs de fonction une douleur énorme.)

Il semble être l'argot Lisper, et je pouvais trouver après une brève définition here, mais de toute façon, je pense Je ne comprends toujours pas:

De nombreuses fermetures ne sont utilisées que pendant la durée des fixations auxquelles elles se rapportent; ceux-ci sont connus sous le nom de "downargs funargs" dans le langage Lisp.

Y avait-il pas Steve Yegge, je venais de me sens stupide maintenant, mais il semble, il pourrait être OK pour demander:

Jamie Zawinski est un héros. Une légende vivante. [...] Un mec qui peut utiliser le terme "downargs funambs" et qui vous lance un regard furieux pour vous demander de l'expliquer, vous crétin.

- XEmacs is dead, long live XEmacs

Ainsi est-il un Lisper ici qui peut compiler ce C-style-programmeurs comme moi?

+1

Je pense que ce que veut dire jwz est, bien qu'il soit compréhensible que les argumentaires en général ne soient pas supportés par java, les arguments descendants auraient pu être supportés sans modification du stockage basé sur la pile des variables fermées. La page wikipedia sur "Funarg_problem" est très claire à ce sujet. –

Répondre

50

Les codes d'accès descendants sont des fonctions locales qui ne sont pas renvoyées ou qui quittent leur portée de déclaration. Ils peuvent seulement être passés vers le bas à d'autres fonctions de la portée actuelle.

Deux exemples. Ceci est une funarg vers le bas:

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

Bien que ce n'est pas:

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

Le premier exemple devrait dire var foo = function ... –

+0

Christian: Eh bien, le premier implique que 'foo' est une fonction définie * n'importe où *, pas nécessairement localement. Je vais clarifier cela. –

+7

Le point principal est que a est sur la pile quand f est exécuté, donc il n'est pas nécessaire de le stocker ailleurs (habituellement avec f sur le tas dans une soi-disant fermeture). Donc "downarg funarg" est la partie facile de "funarg". – starblue

11

Il y a un article très descriptif sur Wiki appelé Funarg problem

« A bas funarg peut également se référer à un état de fonction lorsque cette fonction n'exécute en fait. Cependant, parce que, par définition, l'existence d'un funarg vers le bas est contenue dans l'exécution de la fonction que le crée, l'enregistrement d'activation pour la fonction peut généralement toujours être stocké sur la pile. "

13

en Common Lisp:

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

-> (4 5 6 7) 

En formulaire ci-dessus la fonction lambda est passé RECULER. Lorsqu'elle est appelée par la fonction MAPCAR d'ordre supérieur (qui obtient une fonction et une liste de valeurs comme arguments, puis applique la fonction à chaque élément de la liste et retourne une liste des résultats), la fonction lambda fait toujours référence à la variable 'a' de l'expression LET. Mais tout se passe dans l'expression LET.

Comparez ci-dessus avec cette version:

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

Ici, la fonction lambda est renvoyée par le LET. Vers le haut un peu. Il est ensuite transmis au MAPCAR. Lorsque MAPCAR appelle la fonction lambda, son LET qui l'entoure ne s'exécute plus - la fonction doit toujours faire référence à la variable 'a' du LET.

24

Pour mieux comprendre d'où vient le terme, vous devez connaître l'histoire.

La raison pour laquelle un ancien pirate Lisp peut distinguer vers le bas funargs de funargs en général est que funargs vers le bas sont faciles à mettre en œuvre dans un Lisp traditionnel qui ne dispose pas des variables lexicales, alors que le cas général est difficile.

Traditionnellement, une variable locale a été mis en œuvre dans un interpréteur Lisp en ajoutant un liant (le nom du symbole de la variable, associée à sa valeur) à l'environnement . Un tel environnement était simple à implémenter en utilisant une liste d'associations. Chaque fonction avait son propre environnement et un pointeur vers l'environnement de la fonction parente. Une référence de variable a été résolue en regardant dans l'environnement actuel, et si elle ne s'y trouvait pas, alors dans l'environnement parent, et ainsi de suite jusqu'à la pile d'environnements jusqu'à ce que l'environnement global soit atteint.

Dans une telle implémentation, variables locales ombre variables globales avec le même nom. Par exemple, dans Emacs Lisp, print-length est une variable globale qui spécifie la longueur maximale de la liste à imprimer avant de l'abréger. En liant cette variable autour de l'appel à une fonction, vous pouvez modifier le comportement des instructions d'impression dans cette fonction:

 
(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 ...) 

Vous pouvez voir que dans une telle mise en œuvre, vers le bas funargs sont vraiment faciles à mettre en œuvre, parce que les variables qui sont dans l'environnement de la fonction quand elle est créée seront toujours dans l'environnement de la fonction quand elle est évaluée.

Les variables qui agissent comme celui-ci sont appelés spéciaux ou dynamiques variables et vous pouvez les créer dans Common Lisp en utilisant la déclaration special.

Questions connexes