From: lbolla on
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
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
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
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
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))
First  |  Prev  |  Next  |  Last
Pages: 1 2 3
Prev: ABCL 0.21 released
Next: Do we need a "Stevens" book?