From: ·······@gmail.com
Subject: using a macro to modify an object every time some funciton is called
Date: 
Message-ID: <1171895682.775800.97570@p10g2000cwp.googlegroups.com>
I want to write this macro: given an object with an accessor called
"value", and some function name, and some form, the value is
incremented every time the function is called in the form.

This is using Allegro, so there's a function called "arglist" in here
that makes this non-portable.

(defmacro with-object-increment (object function-name &body body)
  (let ((arglist (arglist function-name)))
    `(labels ((,function-name ,arglist
                              (incf (value ,object))
                              (funcall ',function-name ,@arglist)))
       ,@body)))

I'm starting to think that this is the wrong approach. It seems that
labels only changes the function on the highest level. So if I choose
my function to be factorial, and call (factorial 5) as the body, the
object will increment only once, and all other calls to factorial will
be the main definition, not the labels definition.

From: Joel Wilsson
Subject: Re: using a macro to modify an object every time some funciton is called
Date: 
Message-ID: <1171903459.341316.197740@v45g2000cwv.googlegroups.com>
On Feb 19, 3:34 pm, ········@gmail.com" <·······@gmail.com> wrote:
> I want to write this macro: given an object with an accessor called
> "value", and some function name, and some form, the value is
> incremented every time the function is called in the form.

Not sure if I understood your problem definition correctly.
Is this what you meant?

(defun factorial (n)
  (if (<= n 1)
      1
      (* n (factorial (- n 1)))))

(defclass value-object ()
  ((value :accessor value :initform 0 :initarg :value)))

(defvar *increment* t)
(defmacro with-object-increment (object function-name &body body)
  (let ((actual-function (gensym)))
    `(let ((,actual-function #',function-name))
       (setf (symbol-function ',function-name)
             (lambda (&rest args)
               (when *increment*
                 (incf (value ,object)))
               (let ((*increment* nil))
                 (apply ,actual-function args))))
       (prog1 ,@body
         (setf (symbol-function ',function-name) ,actual-function)))))


For example:
CL-USER> (defparameter *our-value-object* (make-instance 'value-
object :value 0))
*OUR-VALUE-OBJECT*
CL-USER> (with-object-increment *our-value-object* factorial
           (factorial 5)
           (factorial 5))
120
CL-USER> (value *our-value-object*)
2
CL-USER>

I just hacked it together so it's probably not very robust.
Fun exercise, anyways. :)

Regards,
  Joel
From: Joel Wilsson
Subject: Re: using a macro to modify an object every time some funciton is called
Date: 
Message-ID: <1171903747.445836.85020@a75g2000cwd.googlegroups.com>
On Feb 19, 5:44 pm, "Joel Wilsson" <············@gmail.com> wrote:
>        (prog1 ,@body
>          (setf (symbol-function ',function-name) ,actual-function)))))

This should be:
       (prog1 (progn ,@body)
         (setf (symbol-function ',function-name) ,actual-function)))))
From: ·······@gmail.com
Subject: Re: using a macro to modify an object every time some funciton is called
Date: 
Message-ID: <1171916493.600691.212170@t69g2000cwt.googlegroups.com>
On Feb 19, 11:44 am, "Joel Wilsson" <············@gmail.com> wrote:
> On Feb 19, 3:34 pm, ········@gmail.com" <·······@gmail.com> wrote:
>
> > I want to write this macro: given an object with an accessor called
> > "value", and some function name, and some form, the value is
> > incremented every time the function is called in the form.
>
> Not sure if I understood your problem definition correctly.
> Is this what you meant?
>
> (defun factorial (n)
>   (if (<= n 1)
>       1
>       (* n (factorial (- n 1)))))
>
> (defclass value-object ()
>   ((value :accessor value :initform 0 :initarg :value)))
>
> (defvar *increment* t)
> (defmacro with-object-increment (object function-name &body body)
>   (let ((actual-function (gensym)))
>     `(let ((,actual-function #',function-name))
>        (setf (symbol-function ',function-name)
>              (lambda (&rest args)
>                (when *increment*
>                  (incf (value ,object)))
>                (let ((*increment* nil))
>                  (apply ,actual-function args))))
>        (prog1 ,@body
>          (setf (symbol-function ',function-name) ,actual-function)))))
>
> For example:
> CL-USER> (defparameter *our-value-object* (make-instance 'value-
> object :value 0))
> *OUR-VALUE-OBJECT*
> CL-USER> (with-object-increment *our-value-object* factorial
>            (factorial 5)
>            (factorial 5))
> 120
> CL-USER> (value *our-value-object*)
> 2
> CL-USER>
>
> I just hacked it together so it's probably not very robust.
> Fun exercise, anyways. :)
>
> Regards,
>   Joel

I don't know what exactly the difference between my with-object
increment and yours is, since I'm kind of unfamiliar with this whole
macro thing.

My question was can I have a macro that does what that one does, but
at the end (value *our-value-object*) evaluates to 12, since there
were 12 calls* to #'factorial in (factorial 5) (factorial 5)?

Kyle

*Well, ok, there were 10 for yours, but I'm preferring to define
factorial as
(defun factorial (n) (if (= n 0) 1 (* (factorial (- n 1)) n))).
From: Joel Wilsson
Subject: Re: using a macro to modify an object every time some funciton is called
Date: 
Message-ID: <1171918113.823530.5860@k78g2000cwa.googlegroups.com>
On Feb 19, 9:21 pm, ········@gmail.com" <·······@gmail.com> wrote:
> My question was can I have a macro that does what that one does, but
> at the end (value *our-value-object*) evaluates to 12, since there
> were 12 calls* to #'factorial in (factorial 5) (factorial 5)?

You wrote:
"call (factorial 5) as the body, the object will increment only once,
and all other calls to factorial will be the main definition"

>From this I thought you wanted this to increment only once for each
call to the given function:
CL-USER> (with-object-increment *our-value-object* factorial
             (factorial 5)
             (factorial 5))

If you don't want that, simply take out the code for *increment*:
(defmacro with-object-increment (object function-name &body body)
  (let ((actual-function (gensym)))
    `(let ((,actual-function #',function-name))
       (setf (symbol-function ',function-name)
             (lambda (&rest args)
               (incf (value ,object))
               (apply ,actual-function args)))
       (prog1 (progn ,@body)
         (setf (symbol-function ',function-name) ,actual-function)))))

Regards,
  Joel
From: ·······@gmail.com
Subject: Re: using a macro to modify an object every time some funciton is called
Date: 
Message-ID: <1171919730.727732.255530@m58g2000cwm.googlegroups.com>
On Feb 19, 3:48 pm, "Joel Wilsson" <············@gmail.com> wrote:
> On Feb 19, 9:21 pm, ········@gmail.com" <·······@gmail.com> wrote:
>
> > My question was can I have a macro that does what that one does, but
> > at the end (value *our-value-object*) evaluates to 12, since there
> > were 12 calls* to #'factorial in (factorial 5) (factorial 5)?
> You wrote:
>
> "call (factorial 5) as the body, the object will increment only once,
> and all other calls to factorial will be the main definition"
>
> >From this I thought you wanted this to increment only once for each
>
> call to the given function:
> CL-USER> (with-object-increment *our-value-object* factorial
>              (factorial 5)
>              (factorial 5))
>
> If you don't want that, simply take out the code for *increment*:
> (defmacro with-object-increment (object function-name &body body)
>   (let ((actual-function (gensym)))
>     `(let ((,actual-function #',function-name))
>        (setf (symbol-function ',function-name)
>              (lambda (&rest args)
>                (incf (value ,object))
>                (apply ,actual-function args)))
>        (prog1 (progn ,@body)
>          (setf (symbol-function ',function-name) ,actual-function)))))
>
> Regards,
>   Joel

Aha, thanks. I can see how what I posted didn't say what I meant. I'll
look over this.

Kyle
From: Pascal Costanza
Subject: Re: using a macro to modify an object every time some funciton is called
Date: 
Message-ID: <53tuubF1uar6vU1@mid.individual.net>
·······@gmail.com wrote:
> I want to write this macro: given an object with an accessor called
> "value", and some function name, and some form, the value is
> incremented every time the function is called in the form.
> 
> This is using Allegro, so there's a function called "arglist" in here
> that makes this non-portable.
> 
> (defmacro with-object-increment (object function-name &body body)
>   (let ((arglist (arglist function-name)))
>     `(labels ((,function-name ,arglist
>                               (incf (value ,object))
>                               (funcall ',function-name ,@arglist)))
>        ,@body)))
> 
> I'm starting to think that this is the wrong approach. It seems that
> labels only changes the function on the highest level. So if I choose
> my function to be factorial, and call (factorial 5) as the body, the
> object will increment only once, and all other calls to factorial will
> be the main definition, not the labels definition.

1) The arglist issues can easily be resolved. Just expand into the 
following:

`(labels ((,function-name (&rest args)
              (declare (dynamic-extent args))
              (incf (value ,object))
              (apply ',function-name args)))
    ,@body)

2) Yes, when the original function does a recursive call of itself, it 
will not call the shadowing function, because there is no inheritance 
relationship defined. You want something like dynamically scoped 
functions - see http://p-cos.net/documents/dynfun.pdf - or ContextL - 
see http://common-lisp.net/project/closer/contextl.html

With ContextL, you can do the following here:

(define-layered-function function-name (args ...)
   (:method (args ...) ...))

(deflayer object-increment)

(define-layered-method layered-function :before (args ...)
   (incf (value object)))

...and in your client code...

(with-active-layers (object-increment)
   ... some code ...)

There are a number of details to be filled in here, of course, but I 
hope you get the idea...


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: using a macro to modify an object every time some funciton is   called
Date: 
Message-ID: <53urebF1u4lelU1@mid.individual.net>
Pascal Costanza wrote:
> ·······@gmail.com wrote:
>> I want to write this macro: given an object with an accessor called
>> "value", and some function name, and some form, the value is
>> incremented every time the function is called in the form.
>>
>> This is using Allegro, so there's a function called "arglist" in here
>> that makes this non-portable.
>>
>> (defmacro with-object-increment (object function-name &body body)
>>   (let ((arglist (arglist function-name)))
>>     `(labels ((,function-name ,arglist
>>                               (incf (value ,object))
>>                               (funcall ',function-name ,@arglist)))
>>        ,@body)))
>>
>> I'm starting to think that this is the wrong approach. It seems that
>> labels only changes the function on the highest level. So if I choose
>> my function to be factorial, and call (factorial 5) as the body, the
>> object will increment only once, and all other calls to factorial will
>> be the main definition, not the labels definition.
> 
> 1) The arglist issues can easily be resolved. Just expand into the 
> following:
> 
> `(labels ((,function-name (&rest args)
>              (declare (dynamic-extent args))
>              (incf (value ,object))
>              (apply ',function-name args)))
>    ,@body)
> 
> 2) Yes, when the original function does a recursive call of itself, it 
> will not call the shadowing function, because there is no inheritance 
> relationship defined. You want something like dynamically scoped 
> functions
[...]

On second thought, you actually still want something that's lexically 
scoped - something like with-added-methods (see CLtL2). Unfortunately, 
that was never implemented...


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/