Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic function generation with macros

Tags:

common-lisp

I am putting together a macro to generate simple functions of the style:

(defun hello ()
  (format t "hello~&"))

Each new function will have hello replaced.

(defmacro generate-echoers (list)
  `(let ((list-of-functions
         (loop for var in ,list
            collect
              `(defun ,(intern var) ()
                 (format t ,(concatenate var "~&"))))))
  `(progn
     ,list-of-functions)))

I developed the above function, which demonstrates conclusively that I have not yet masted quote-times and phases of expansion.

The desired usage is as follows: (generate-echoers '("hi" "ping" "pong")) => ;A list of functions that each say their name, as HELLO does above.

like image 769
Paul Nathan Avatar asked Sep 16 '26 04:09

Paul Nathan


2 Answers

A function to generate:

(defun hello ()
  (format t "hello~&"))

I would first write a function which creates above code:

(defun make-echoers (name)
  `(defun ,(intern (string-upcase name)) ()
     (format t ,(concatenate 'string name "~&"))))

Note that symbols are by default uppercase in Common Lisp - so we are using uppercase, too.

Then you can test it:

CL-USER 1 > (make-echoers "hello")
(DEFUN HELLO NIL (FORMAT T "hello~&"))

Works. Now let's use it:

(defmacro generate-echoers (list)
  `(progn ,@(mapcar #'make-echoers list)))

Test it:

CL-USER 2 > (macroexpand-1 '(generate-echoers ("hi" "ping" "pong")))
(PROGN
  (DEFUN HI NIL (FORMAT T "hi~&"))
  (DEFUN PING NIL (FORMAT T "ping~&"))
  (DEFUN PONG NIL (FORMAT T "pong~&")))
like image 106
Rainer Joswig Avatar answered Sep 19 '26 13:09

Rainer Joswig


Your code can be simplified and made more correct like this:

(defmacro generate-echoers (list)
  `(progn ,@(loop :for var :in list
               :collect `(defun ,(intern (format nil "~:@(~A~)" var)) ()
                           (format t ,(concatenate 'string var "~&"))))))

First of all, you've got to splice the loop's result into the generated body.

Also you've forgotten, that concatenate takes type parameter and to upcase all your vars (otherwise you'll get function names like |foo|).

like image 29
Vsevolod Dyomkin Avatar answered Sep 19 '26 13:09

Vsevolod Dyomkin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!