tags:

views:

52

answers:

2

I'm fairly new to lisp but I've been playing around with it. I have several problems which I need clarifying. Below is my little macro that I defined.

(defmacro transform (query)
 '(lambda (row)
   (eq (nth 1 query) (nth 0 (nth 0 row)))
  )
)

I'm just wondering, how can I specify the function to use in the body dynamically? Like say if I want to use the "+" or "-" function instead of "eq", or even another function that I defined? Like I thought it'd be possible to pass in the name of the function as a parameter but that obviously doesn't work. I also get variable unbound errors when I modify the list (query) that's passed in.

I'm still trying to get my head around functional programming so please bare with me if I make any silly mistakes.

A: 

funcall is the answer! Decided to just pass it in and use funcall to evaluate the function.

PCBEEF
+1  A: 

In the body of the macro, you can use all of Lisp's run-time library to generate the actual expansion. So, for example:

(defmacro transform (query &key (test 'eq))
   (let ((row-var (gensym)))
     `(lambda (,row-var) 
        (,test (nth 1 ,query) (nth 0 (nth 0 ,row-var))))))

This version uses the "backtick" instead of a plain apostrophe, which allows for "unquoting" of forms within the body, thus allowing the inclusion of generated forms into the result.

You can use this macro like your original version:

(transform (...))

or (passing an explicit test function):

(transform (...) :test equal)

Note, that you should not use plain symbols as variable names in macro expansions (as your row argument to the generated lambda expression) as that might accidentally interfer with the use of that symbol at the site of the use of your macro. You simply don't know when writing your macro, whether there will be a variable called row somewhere when your macro is used, and whether it is not already used within the query form/expression. Your original definition would "capture" the variable, possibly altering the meaning of whatever query does.

Dirk