Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lexical closures over macrolet?

Tags:

Is there a way to do something like lexical closures using macrolet? What I want to do is make the following macro a local recursive helper that calls a function on each combination instead of generating a list as it does now calling the macro in the repl results in:

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

What I would like is a macro that takes a function and any number of lists and results in nested loops that call the function on each combination. I'm pretty new to lisp, this is the first macro I've written beyond 'nif' clones and the like so any suggestions are appreciated.

I've tried to turn the macro into a macrolet in a macro that takes a function and the line '(nreverse (list ,item ,@vars))' is replaced with '(func (nreverse (list ,item ,@vars)))' but I get errors saying that func is an undefined variable or function.

This is the original function:

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

This is what I've tried with macrolet and get undefined function 'func' errors.

(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)))
like image 394
asm Avatar asked Feb 20 '10 02:02

asm


1 Answers

Macros are not first-class objects in Common Lisp, so you can't really have the equivalent of a lexical closure as a macro. You could get a similar effect by creating a function that generates a list that is a valid Lisp program, and then evals it.

That probably isn't a very good solution to your problem though. As Rainer Joswig said, macros are for manipulating source code. Use them when you want a new syntactic form that isn't built in to the language. Don't use them where you can write what you want with ordinary functions.

like image 81
Zak Avatar answered Oct 11 '22 10:10

Zak