2010-02-20 13 views
5

¿Hay alguna manera de hacer algo como cierres léxicos usando macrolet? Lo que quiero hacer es la siguiente macro un ayudante recursiva local que llama a una función en cada combinación en lugar de generar una lista como lo hace ahora llamar a la macro en los resultados repl en:cierres léxicos sobre 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)) 

lo que le gustaría es una macro que toma una función y cualquier cantidad de listas y resultados en bucles anidados que llaman a la función en cada combinación. Soy bastante nuevo para lisp, esta es la primera macro que he escrito más allá de los clones 'nif' y similares, así que cualquier sugerencia es apreciada.

He intentado convertir la macro en una macrolet en una macro que toma una función y la línea '(nreverse (list, item, @ vars))' se reemplaza por '(func (nreverse (list, item) , @ vars))) 'pero recibo errores que dicen que func es una variable o función indefinida.

Ésta es la función original:

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

Esto es lo que he tratado con macrolet y recibo errores 'func' de función no definida.

(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

¿Puedes explicar por qué quieres usar macros para esto? ¿Qué debería (dejar ((a '((1 2 3) (4 5 6)))) (combinaciones nil a)) hacer? –

+0

Debe devolver '(((1 2 3)) ((4 5 6))) que es una lista de todas las combinaciones que toman un elemento de cada lista de entrada por combinación. Estoy haciendo esto con una macro porque eso es lo que he estado explorando en este momento. Podría hacerlo sin macros, pero quería intentar escribir una macro más compleja que nif. Esto me da la oportunidad de descubrir qué se puede y no se puede hacer, nunca me hubiera preguntado si se puede usar un macrolet de esta manera. Espero que una vez que termine esto comprenda las macros mucho mejor. – asm

+2

No creo que esto tenga sentido hacerlo con una macro. Las macros están ahí para calcular el código fuente, no los datos. Si desea calcular los datos, los datos deben estar allí en el momento de la expansión de macros, lo cual no es habitual. –

Respuesta

5

macros no son objetos de primera clase en Common Lisp, así que realmente no se puede tener el equivalente de un cierre léxica como una macro. Puede obtener un efecto similar creando una función que genere una lista que sea un programa Lisp válido y luego la evalúe.

Sin embargo, probablemente esta no sea una muy buena solución a su problema. Como dijo Rainer Joswig, las macros son para manipular el código fuente. Úselos cuando desee una nueva forma sintáctica que no esté integrada en el idioma. No los use donde pueda escribir lo que quiera con funciones comunes.

+0

Bien, me convenciste. Supongo que este es el final de la línea para esta exploración. – asm

+0

@Andrew Myers: ha habido algunas exploraciones de la idea de las macros de primera clase. El más reciente sobre el que leí fue sobre Paul Graham considerando la idea de Arc. Creo que terminó archivado porque hizo el compilador mucho más complejo para beneficios inciertos. – Zak