2010-02-20 5 views
5

Existe-t-il un moyen de faire quelque chose comme des fermetures lexicales en utilisant macrolet? Ce que je veux faire est la macro suivante une aide récursive locale qui appelle une fonction sur chaque combinaison au lieu de générer une liste car il n'appelle maintenant la macro dans les résultats de repl dans:Fermetures lexicales sur macrolet?

CL-USER> (combinations nil '(1 2 3) '(4 5 6)) 
((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6)) 

Ce que je voudrais est une macro qui prend une fonction et un nombre quelconque de listes et entraîne des boucles imbriquées qui appellent la fonction sur chaque combinaison. Je suis assez nouveau pour le lisp, c'est la première macro que j'ai écrite au-delà des clones 'nif' et ainsi de suite, donc toutes les suggestions sont appréciées.

J'ai essayé de transformer la macro en macrolet dans une macro qui prend une fonction et la ligne '(nreverse (liste, item, @ vars))' est remplacée par '(func (nreverse (liste, item , @ vars))) 'mais j'obtiens des erreurs en disant que func est une variable indéfinie ou une fonction.

Ceci est la fonction originale:

(defmacro combinations (vars &rest lsts) 
    (with-gensyms (item) 
    `(loop for ,item in ,(car lsts) ,(if (null (cdr lsts)) 'collecting 'nconcing) 
     ,(if (null (cdr lsts)) 
      `(nreverse (list ,item ,@vars)) 
      `(combinations (,item ,@vars) ,@(cdr lsts)))))) 

C'est ce que je l'ai essayé avec macrolet et obtenir des erreurs « » fonc fonction non définie.

(defmacro for-all-combonations (func &rest lst) 
     (macrolet ((for-all (vars &rest lsts) 
        (with-gensyms (item) 
         `(loop for ,item in ,(car lsts) ,(if (null (cdr lsts)) 
                  'collecting 'nconcing) 
          ,(if (null (cdr lsts)) 
           `(func (nreverse (list ,item ,@vars))) 
           `(for-all (,item ,@vars) ,@(cdr lsts))))))) 
     (for-all nil lst))) 
+2

pouvez-vous expliquer pourquoi vous souhaitez utiliser des macros pour cela? Que devrait (let ((a ((1 2 3) (4 5 6)))) (combinaisons nil a)) faire? –

+0

Il devrait retourner '(((1 2 3)) ((4 5 6))) qui est une liste de toutes les combinaisons prenant un élément de chaque liste d'entrée par combinaison. Je le fais avec une macro parce que c'est ce que j'ai exploré en ce moment. Je pourrais le faire sans macros mais je voulais essayer d'écrire une macro plus complexe que nif. Cela me donne une chance de savoir ce qui peut et ne peut pas être fait, je ne me serais jamais demandé si un macrolet peut être utilisé de cette façon autrement. J'espère qu'une fois que j'aurai terminé cela, je comprendrai mieux les macros. – asm

+2

Je ne pense pas que cela ait un sens à faire avec une macro. Les macros sont là pour calculer le code source, pas les données. Si vous voulez calculer des données, les données doivent être présentes au moment de l'expansion de la macro - ce qui n'est pas habituel. –

Répondre

5

Les macros sont des objets pas de première classe en Common Lisp, donc vous ne pouvez pas vraiment avoir l'équivalent d'une fermeture lexicale comme une macro. Vous pourriez obtenir un effet similaire en créant une fonction qui génère une liste qui est un programme Lisp valide, puis l'évalue.

Ce n'est probablement pas une très bonne solution à votre problème. Comme l'a dit Rainer Joswig, les macros servent à manipuler le code source. Utilisez-les quand vous voulez un nouveau formulaire syntaxique qui n'est pas intégré à la langue. Ne les utilisez pas où vous pouvez écrire ce que vous voulez avec des fonctions ordinaires.

+0

Très bien, vous m'avez convaincu. Je suppose que c'est la fin de la ligne pour cette exploration. – asm

+0

@Andrew Myers - il y a eu quelques explorations de l'idée de macros de première classe. Le plus récent que j'ai lu était Paul Graham considérant l'idée d'Arc. Je pense qu'il a fini par le mettre à l'écart parce qu'il rendait le compilateur beaucoup plus complexe pour des avantages incertains. – Zak