views:

90

answers:

1

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)))
+4  A: 

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.

Zak
Alright, you convinced me. I guess this is the end of the line for this exploration.
Andrew Myers
@Andrew Myers - there have been a few explorations of the idea of first-class macros. The most recent I read about was Paul Graham considering the idea for Arc. I think he ended up shelving it because it made the compiler much more complex for uncertain benefits.
Zak