Prev: ABCL 0.21 released
Next: Do we need a "Stevens" book?
From: lbolla on 29 Jul 2010 12:12 On 29 July, 16:44, Alessio Stalla <alessiosta...(a)gmail.com> wrote: > On Jul 29, 5:22 pm, lbolla <lbo...(a)gmail.com> wrote: > > > > > > > Hi all, > > I have a macro that defines functions, like this: > > > (defmacro my-defun ((name &rest rest)) > > `(defun ,name () > > (list ,@rest))) > > > and I want to call it many time, with different arguments, like that: > > (my-defun (f1 1)) > > (my-defun (f2 2)) > > (my-defun (f3 3)) > > > I'd like to use mapcar, like this: > > (mapcar #'my-defun '((f1 1) (f2 2) (f3 3))) ; error! my-defun is not a > > function > > > but this does not work, because my-defun is not a function. > > How would you do? > > There's more than one way to do it, and with different semantics. > Interpreting strictly what you said, you are asking how to apply a > macro function *at runtime* on a sequence of expressions that > represent invocations of that macro, obtaining a list of forms, which > are the result of macroexpansion on each input expression. I'll > assume, however, that you want to apply a macro to multiple forms *at > compile time*, which is probably what you intended to do. Since you > want it to happen at compile time, you need to write a macro for it, > for example: > > (defmacro generate-calls (operator &rest arglists) > `(progn > ,@(mapcar (lambda (arglist) `(,operator ,@arglist)) arglists))) > > and use it like this: > > (generate-calls my-defun (f1 1) (f2 2) (f3 3)) > > in fact, (macroexpand '(generate-calls my-defun (f1 1) (f2 2) (f3 3))) > ==> (PROGN (MY-DEFUN F1 1) (MY-DEFUN F2 2) (MY-DEFUN F3 3)) > > hth, > Alessio Thanks, this is exactly what I meant! Now, I wonder if I really want to do it a runtime or at compile time... Cheers, L.
From: Pascal J. Bourguignon on 29 Jul 2010 12:20 Peter Keller <psilord(a)cs.wisc.edu> writes: > Pascal J. Bourguignon <pjb(a)informatimago.com> wrote: >> lbolla <lbolla(a)gmail.com> writes: >> >>> Hi all, >>> I have a macro that defines functions, like this: >>> >>> (defmacro my-defun ((name &rest rest)) >>> `(defun ,name () >>> (list ,@rest))) >>> >>> and I want to call it many time, with different arguments, like that: >>> (my-defun (f1 1)) >>> (my-defun (f2 2)) >>> (my-defun (f3 3)) >>> >>> I'd like to use mapcar, like this: >>> (mapcar #'my-defun '((f1 1) (f2 2) (f3 3))) ; error! my-defun is not a >>> function >>> >>> but this does not work, because my-defun is not a function. >>> How would you do? >> >> Make it a function! >> >> (defun my-defun* (nr) >> (destructuring-bind (name &rest rest) nr >> (setf (fdefinition name) (compile nil `(lambda () (block ,name (list ,@rest))))) >> name)) >> >> (mapcar (function funcall) (mapcar (function my-defun*) '((f1 1) (f2 1 2) (f3 1 2 3)))) >> --> ((1) (1 2) (1 2 3)) >> > > Although, if I understand correctly, and correct me if I don't, that isn't > exactly the same thing because compile enforces a NIL lexical environment. Right but then, there's no way to generate code dynamically into a clojure, other than passing explicitely the free variables you want. That is, if you really want to do: (let ((a 1) (b 2) (c 3)) (mapcar (function my-defun*) '((f1 a) (f2 b) (f3 c)))) you already see there's a slight problem since a, b and c are quoted. You would have to write: (let ((a 1) (b 2) (c 3)) (mapcar (lambda (nr) (my-defun* nr (list (list 'a (& a)) ; builds explicitely an environment for f1, f2, and f3. (list 'b (& b)) ; and collecting _places_, (list 'c (& c))))) ; so that you can write: '((f1 (incf a)) (f2 (decf a) b) (f3 c)))) with: (defmacro & (var) (let ((m (gensym)) (v (gensym))) `(lambda (,m &optional ,v) (ecase ,m ((get) ,var) ((set) (setf ,var ,v)))))) (defun deref (locative) (funcall locative 'get)) (defun (setf deref) (value locative) (funcall locative 'set value)) (defun my-defun* (nr bindings) (let ((temps (loop repeat (length bindings) collect (gensym)))) (destructuring-bind (name &rest rest) nr (setf (fdefinition name) (compile nil `(lambda () (block ,name (let ,(mapcar (lambda (var binding) (list var (second binding))) temps bindings) (symbol-macrolet ,(mapcar (lambda (temp binding) `(,(car binding) (deref ,temp))) temps bindings) (list ,@rest))))))) name))) So that: CL-USER> (let ((a 42)) (my-defun* '(f1 (incf a)) (list (list 'a (& a))))) F1 CL-USER> (list (f1) (f1) (f1)) ((43) (44) (45)) and now: (let ((a 1) (b 2) (c 3)) (values (mapcar (function funcall) (mapcar (lambda (nr) (my-defun* nr (list (list 'a (& a)) ; builds explicitely an environment for f1, f2, and f3. (list 'b (& b)) ; and collecting _places_, (list 'c (& c))))) ; so that you can write: '((f1 (incf a) (incf c)) (f2 (decf a) b (incf c)) (f3 (incf c))))) (list a b c))) --> ((2 4) (1 2 5) (6)) ; (1 2 6) -- __Pascal Bourguignon__ http://www.informatimago.com/
From: Alessio Stalla on 29 Jul 2010 13:48 On 29 Lug, 18:12, lbolla <lbo...(a)gmail.com> wrote: > On 29 July, 16:44, Alessio Stalla <alessiosta...(a)gmail.com> wrote: > > > > > On Jul 29, 5:22 pm, lbolla <lbo...(a)gmail.com> wrote: > > > > Hi all, > > > I have a macro that defines functions, like this: > > > > (defmacro my-defun ((name &rest rest)) > > > `(defun ,name () > > > (list ,@rest))) > > > > and I want to call it many time, with different arguments, like that: > > > (my-defun (f1 1)) > > > (my-defun (f2 2)) > > > (my-defun (f3 3)) > > > > I'd like to use mapcar, like this: > > > (mapcar #'my-defun '((f1 1) (f2 2) (f3 3))) ; error! my-defun is not a > > > function > > > > but this does not work, because my-defun is not a function. > > > How would you do? > > > There's more than one way to do it, and with different semantics. > > Interpreting strictly what you said, you are asking how to apply a > > macro function *at runtime* on a sequence of expressions that > > represent invocations of that macro, obtaining a list of forms, which > > are the result of macroexpansion on each input expression. I'll > > assume, however, that you want to apply a macro to multiple forms *at > > compile time*, which is probably what you intended to do. Since you > > want it to happen at compile time, you need to write a macro for it, > > for example: > > > (defmacro generate-calls (operator &rest arglists) > > `(progn > > ,@(mapcar (lambda (arglist) `(,operator ,@arglist)) arglists))) > > > and use it like this: > > > (generate-calls my-defun (f1 1) (f2 2) (f3 3)) > > > in fact, (macroexpand '(generate-calls my-defun (f1 1) (f2 2) (f3 3))) > > ==> (PROGN (MY-DEFUN F1 1) (MY-DEFUN F2 2) (MY-DEFUN F3 3)) > > > hth, > > Alessio > > Thanks, this is exactly what I meant! > Now, I wonder if I really want to do it a runtime or at compile > time... If you do at compile time, you will include the result of expanding the macros in the source code of your programs, just as if you had written the macro calls manually instead of iterating programmatically. If you do it at runtime, you will get a list containing the results of the macroexpansions, i.e. you won't actually run any code (unless you use eval or compile on the elements of the aforementioned list). It's up to you to decide which strategy makes sense in your case, and how to structure your code consequently (if you want to do it at runtime, then using a function rather than a macro like Pascal suggested is arguably a better choice). Cheers, Alessio
From: Scott L. Burson on 29 Jul 2010 15:31 On Jul 29, 9:20 am, p...(a)informatimago.com (Pascal J. Bourguignon) wrote: > > Right but then, there's no way to generate code dynamically into a > clojure Hmm, a Freudian slip?? :) :) :) -- Scott
From: Captain Obvious on 30 Jul 2010 04:48
l> (defmacro my-defun ((name &rest rest)) l> `(defun ,name () l> (list ,@rest))) l> and I want to call it many time, with different arguments, like that: l> (my-defun (f1 1)) l> (my-defun (f2 2)) l> (my-defun (f3 3)) l> I'd like to use mapcar, like this: l> (mapcar #'my-defun '((f1 1) (f2 2) (f3 3))) ; error! my-defun is not a l> function l> but this does not work, because my-defun is not a function. l> How would you do? Two other options (not necessarily good ones): (macrolet ((defuns (lst) `(progn ,@(loop for form in lst collect `(my-defun ,form)))) (defuns ((f1 1) (f2 2) (f3 3))) #.`(progn ,@(loop for form in '((f1 1) (f2 2) (f3 3)) collect `(my-defun ,form)) |