7
votes

Utilisation d'une valeur Lambda de fonction comme premier élément de la liste

Je lis sur les paradigmes de Peter Norvig de la programmation d'intelligence artificielle et je suis tombé sur une question que je ne peux pas résoudre seul (c'est mon introduction à la LISP). Le problème est assez petit, vraiment, mais évidemment, pas un mon petit cerveau ne peut résoudre.

Pourquoi est-ce que lorsque la valeur d'une fonction est une Lambda, il s'agit d'une erreur d'utiliser cette fonction comme premier élément à une liste . Par exemple: P>

LISP: P>

(defun some-func ()
  #'(lambda (x) x))

;; At REPL
;; Does not work
> ((some-func) 1)
;; Does work
> ((lambda (x) x) 1)
;; Also works
> (funcall (some-func) 1)


0 commentaires

4 Réponses :


4
votes

((Lambda (x) ...) ...) est un cas spécial codé dans les règles de l'évaluateur. Cela n'évalue pas le premier élément sous la forme et en utilisant le résultat en tant que cas général. Il est normal que vous ayez à utiliser FunCall ou Appliquer pour appeler une fonction qui résulte de l'évaluation d'une autre forme.


1 commentaires

À droite, je pense que c'est ce qui est décrit par CLHS 3.1.2.1.2.4 (!!): "Une forme Lambda équivaut à utiliser Funcall d'une fermeture lexicale de l'expression de Lambda sur les arguments donnés." lispworks.com/documentation/hyperspec/body/03_ababd.htm



6
votes

C'est une bonne question et une question où les LISP communes peuvent être assez déroutantes. La chose est qu'en raison des raisons historiques, les LISP communes ont deux espaces de noms - un pour les fonctions et une autre pour les valeurs. Pour ce faire, il existe deux règles d'évaluation différentes pour la position de la tête d'une application de fonction et pour le reste - le premier évaluera un symbole en tant que nom de la fonction, et la seconde évaluera un symbole comme une référence variable. Il existe évidemment des cas lorsque la valeur est en fait une fonction - par exemple, si vous écrivez une fonction MapCar , vous voudrez faire quelque chose comme xxx

mais Cela ne fonctionnera pas - il se plaint de f être une fonction inconnue. Pour ces cas, il existe une fonction spéciale appelée Funcall , qui reçoit une fonction et un argument de la fonction, et appliquera la fonction comme d'habitude - et puisque Funcall est une simple Fonction, ses arguments sont tous évalués comme d'habitude (en tant que valeurs). De sorte que ce qui précède doit être corrigé en l'utilisant: xxx

comme vous soupçonnez probablement maintenant, il y a les cas miroirs - où vous souhaitez évaluer quelque chose en tant que fonction et pas comme valeur. Par exemple, cela ne fonctionne pas: xxx

car il fait référence à la variable 1 + et non la fonction. Pour ces cas, il existe une forme spéciale appelée fonction qui évalue son contenu en tant que fonction et le renvoie comme valeur: xxx

et il peut être abrégé avec # ': xxx

Ce n'est pas la fin de cette histoire - pour donner quelques exemples:

  • Dans certains cas, un nom cité simple peut fonctionner en fonction - par exemple '1 + dans le dernier exemple de travail - mais c'est une sorte de piratage capable de voir Seuls les noms liés à l'échelle mondiale, donc # ' est presque toujours meilleur

  • Un hack similaire peut être utilisé avec lambda - afin que vous puissiez utiliser (my-mapcar '(lambda (x) (1+ x)' (1 2 3)) , en fait, vous pouvez utiliser (liste 'lambda' (x) '(1+ x)) qui est encore pire (et IIRC, non portable), mais en utilisant (lambda (x) (1+ x)) fonctionne car il est implicitement enveloppé dans un # ' (essayez de développer un lambda formulaire macro et vous le verrez). Un hack associé permet d'utiliser une expression lambda comme la tête d'une application de fonction (qui est l'une des choses que vous avez essayées).

  • laisse etc lier des valeurs locales, et dans certains cas, vous voudrez lier les fonctions locales à la place - pour cela, il existe de nouvelles constructions de liaison: flect et étiquettes

    Si tout cela a l'air étrange et / ou trop compliqué, alors vous n'êtes pas seul. C'est l'une des principales différences entre les LISP et le schéma commun. (La différence conduit ensuite à des changements d'idiomes communs dans les deux langues: le code de régime tend à utiliser des fonctions d'ordre supérieur beaucoup plus fréquemment que le code LISP commun. Comme d'habitude avec ce genre de questions religieuses, certaines personnes se disputent en faveur de ce que CL fait, réclamant que les fonctions d'ordre supérieur sont déroutantes, elles aiment donc le rappel explicite en code.)


5 commentaires

Merci, Eli, pour prendre le temps d'écrire ceci; Cela a aidé un tas! Je ne peux pas vous uplifier maintenant, mais quand je peux - je le ferai. Merci encore.


Je trouve la séparation des espaces de noms de fonction et de variables très utiles et je crée et utilise fréquemment des fonctions d'ordre supérieur.


La citation Lambda ne fonctionne pas dans les LISP commun. (My-Mapcar '(Lambda (x) ...) ...) n'est pas une LISP courante et générera une erreur. Consérant comme une liste ne fonctionnera pas non plus dans les LISP commun. Je devinerais également que la LISP commune utilise au moins une fonction d'ordre plus élevé comme système. Par exemple, plusieurs fonctions prennent des fonctions telles que la clé et le test comme des arguments, dans lesquels le schéma fournit plusieurs versions pour EQ, EQL et égal.


Svante: Oui, j'ai dit que la préférence est religieuse. Quant à toute comparaison anecdotique entre combien de fonctions HO, vous utilisez vs personne d'autre - c'est exactement le type de "discussion" qui ne conduit nulle part. Mon "tend à" est évidemment subjectif aussi; Il repose exactement sur le fait que Clers prétendent souvent qu'ils préfèrent la distinction explicite. Il est clair pour moi comment vous procédiez pour contrer cela et, comme il est subjectif, alors soyez-le. Le point principal (qui deviendra plus fort) est que cela est avant tout un problème religieux.


Rainer: Vous avez raison - j'aurais dû préciser que "IIRC, non portable" s'applique aux deux formes d'une expression de Lambda citée qui précède cela. (Et BTW, qui a travaillé pour moi à Allegro et (comme prévu) cela ne fonctionne pas dans Clisp.) (Et BTW # 2, j'ai envisagé de mentionner NewLisp comme une expérience intéressante dans la promotion de la question fondamentale, mais c'est probablement divergeant trop loin.)



2
votes

La raison principale Lisp ne permet pas une fonction qui renvoie une Lambda comme le premier élément d'une expression a à voir avec la distinction entre LISP-1 et LISP-2 .

si commun lisp autorisé ((((certains-func) 1) Pour être équivalent à (Funcall (certains-func) 1) , il pourrait être perçu comme incohérent Pour ne pas permettre également de dire (let (((f # 'Certains-func)) (F 1)) plutôt que nécessitent (funcall F 1) .


0 commentaires

1
votes

Il existe en fait une très bonne justification de ne pas soutenir de telles formes: elles sont ambiguës. Considérons la façon dont noms de fonction sont définis en commun LISP:

Nom de la fonction n . 1. (Dans un Environnement ) A ou a list (symbole SETF) c'est le Nom d'une fonction dans cet environnement . 2. A ou une liste (symbole SETF) .

Compte tenu de cela, comment une forme comme le comportement suivant se comporter? xxx

Si cet ensemble x valeur 10 ou doit-il exécuter le formulaire (SETF voiture) (qui serait une erreur) et essayez d'utiliser sa valeur de retour en tant que fonction pour appeler avec les arguments < Code> 10 et x ? Les LISP communes spécifient ni comportement, et ce n'est pas du tout clair pour moi que c'est un mauvais choix. Après tout, autant que je sache, rien dans la norme n'empêche que les implémentations conformes d'extension de la définition de formulaires valides pour prendre en charge une gamme plus large de noms d'opérateurs (les fonctions SETF de boîtier spéciales ne vous aideraient pas vraiment ici, non plus).


1 commentaires

Intéressant. Je m'attendrais à ce que la forme intérieure soit exécutée et que la valeur de celle-ci soit utilisée comme fonction (ou nom de fonction - je suis toujours un peu confus quant à la différence entre les deux et où les deux sont utilisées). Cependant, je me tromperais bien sûr, comme le prouve ce fil! Il h. Je suppose que cela a du sens lorsque vous envisagez les règles d'évaluation; Néanmoins, c'est un peu déroutant au début (et peut-être un peu de temps après).