From: fireblade
Subject: ,@ with functions, *weird* macro behaviour
Date: 
Message-ID: <1181806063.047543.269510@g37g2000prf.googlegroups.com>
I have a macro that get's 2 functions (exist-p of 1 argument) and add-
values (variable number of arguments)

(defmacro add-tuple (exist-p add-values &rest values)
  `(multiple-value-bind (result error)
      (ignore-errors
        (funcall ,exist-p (car ',values)))
    (cond ((typep error 'error)
           (values
            "Database error occured1"
            t))
          (result
           (values
            (string+  (car ',values) " exists.")
            nil))
          (t
           (multiple-value-bind (result error)
               (ignore-errors
                 (funcall ,add-values ,@values))
             (if (typep error 'error)
               (values
                "database error occured2"
                t)
               (values
                (string+  (car ',values) " inserted.")
                nil)))))))

When I call the macro directly like :
(1)
(add-tuple #'authority-exist-p #'add-authority-values authority
description))

But wrapped in a function makes a problem :

(2)
(defun add-authority (authority description)
  (add-tuple #'authority-exist-p #'add-authority-values authority
description))

Wrapped in another macro like:
(3)
(defmacro add-authority (authority description)
  `(add-tuple #'authority-exist-p #'add-authority-
values ,authority ,description))

and everything is fine again.
What is the difference between (2) and (3).


I prefer function wrapper because i could pass it as arguments,
funcall it etc.
So I rewrite it like this:

(defun add-tuple (exist-p add-values  &rest values)
 (multiple-value-bind (result error)
      (ignore-errors
          (funcall exist-p (car values)))
    (cond ((typep error 'error)
           (values
            "Database error occured."
            t))
          (result
           (values
            (string+  (car values) " already exists.")
            nil))
          (t
           (multiple-value-bind (result error)
               (ignore-errors
                 (eval ; explicitly calling eval
                    `(funcall ,add-values ,@values)))
             (if (typep error 'error)
               (values
                "database error occured."
                t)
               (values
                (string+  (car values) " inserted.")
                nil)))))))

Which works like a charm, with functional wrapper.The problem is in
the explicit call of eval.Performance issues right?So  is it possible
to somehow rewrite it as function without eval.


Slobodan Blazeski

From: sross
Subject: Re: ,@ with functions, *weird* macro behaviour
Date: 
Message-ID: <1181815100.273853.299950@e9g2000prf.googlegroups.com>
On Jun 14, 8:27 am, fireblade <·················@gmail.com> wrote:
> I have a macro that get's 2 functions (exist-p of 1 argument) and add-
> values (variable number of arguments)
>
> (defmacro add-tuple (exist-p add-values &rest values)
>   `(multiple-value-bind (result error)
>       (ignore-errors
>         (funcall ,exist-p (car ',values)))
>     (cond ((typep error 'error)
>            (values
>             "Database error occured1"
>             t))
>           (result
>            (values
>             (string+  (car ',values) " exists.")
>             nil))
>           (t
>            (multiple-value-bind (result error)
>                (ignore-errors
>                  (funcall ,add-values ,@values))
>              (if (typep error 'error)
>                (values
>                 "database error occured2"
>                 t)
>                (values
>                 (string+  (car ',values) " inserted.")
>                 nil)))))))
>
> When I call the macro directly like :
> (1)
> (add-tuple #'authority-exist-p #'add-authority-values authority
> description))
>
> But wrapped in a function makes a problem :
>
> (2)
> (defun add-authority (authority description)
>   (add-tuple #'authority-exist-p #'add-authority-values authority
> description))
>
> Wrapped in another macro like:
> (3)
> (defmacro add-authority (authority description)
>   `(add-tuple #'authority-exist-p #'add-authority-
> values ,authority ,description))
>
> and everything is fine again.
> What is the difference between (2) and (3).
>
> I prefer function wrapper because i could pass it as arguments,
> funcall it etc.
> So I rewrite it like this:
>
> (defun add-tuple (exist-p add-values  &rest values)
>  (multiple-value-bind (result error)
>       (ignore-errors
>           (funcall exist-p (car values)))
>     (cond ((typep error 'error)
>            (values
>             "Database error occured."
>             t))
>           (result
>            (values
>             (string+  (car values) " already exists.")
>             nil))
>           (t
>            (multiple-value-bind (result error)
>                (ignore-errors
>                  (eval ; explicitly calling eval
>                     `(funcall ,add-values ,@values)))
>              (if (typep error 'error)
>                (values
>                 "database error occured."
>                 t)
>                (values
>                 (string+  (car values) " inserted.")
>                 nil)))))))
>
> Which works like a charm, with functional wrapper.The problem is in
> the explicit call of eval.Performance issues right?So  is it possible
> to somehow rewrite it as function without eval.

Style issues actually.
Yes, try (apply add-values values)

and I'd still recommend looking at handler-bind.

Sean.
From: fireblade
Subject: Re: ,@ with functions, *weird* macro behaviour
Date: 
Message-ID: <1181891725.741902.122500@k79g2000hse.googlegroups.com>
On Jun 14, 11:58 am, sross <······@gmail.com> wrote:
> On Jun 14, 8:27 am, fireblade <·················@gmail.com> wrote:
>
>
>
>
>
> > I have a macro that get's 2 functions (exist-p of 1 argument) and add-
> > values (variable number of arguments)
>
> > (defmacro add-tuple (exist-p add-values &rest values)
> >   `(multiple-value-bind (result error)
> >       (ignore-errors
> >         (funcall ,exist-p (car ',values)))
> >     (cond ((typep error 'error)
> >            (values
> >             "Database error occured1"
> >             t))
> >           (result
> >            (values
> >             (string+  (car ',values) " exists.")
> >             nil))
> >           (t
> >            (multiple-value-bind (result error)
> >                (ignore-errors
> >                  (funcall ,add-values ,@values))
> >              (if (typep error 'error)
> >                (values
> >                 "database error occured2"
> >                 t)
> >                (values
> >                 (string+  (car ',values) " inserted.")
> >                 nil)))))))
>
> > When I call the macro directly like :
> > (1)
> > (add-tuple #'authority-exist-p #'add-authority-values authority
> > description))
>
> > But wrapped in a function makes a problem :
>
> > (2)
> > (defun add-authority (authority description)
> >   (add-tuple #'authority-exist-p #'add-authority-values authority
> > description))
>
> > Wrapped in another macro like:
> > (3)
> > (defmacro add-authority (authority description)
> >   `(add-tuple #'authority-exist-p #'add-authority-
> > values ,authority ,description))
>
> > and everything is fine again.
> > What is the difference between (2) and (3).
>
> > I prefer function wrapper because i could pass it as arguments,
> > funcall it etc.
> > So I rewrite it like this:
>
> > (defun add-tuple (exist-p add-values  &rest values)
> >  (multiple-value-bind (result error)
> >       (ignore-errors
> >           (funcall exist-p (car values)))
> >     (cond ((typep error 'error)
> >            (values
> >             "Database error occured."
> >             t))
> >           (result
> >            (values
> >             (string+  (car values) " already exists.")
> >             nil))
> >           (t
> >            (multiple-value-bind (result error)
> >                (ignore-errors
> >                  (eval ; explicitly calling eval
> >                     `(funcall ,add-values ,@values)))
> >              (if (typep error 'error)
> >                (values
> >                 "database error occured."
> >                 t)
> >                (values
> >                 (string+  (car values) " inserted.")
> >                 nil)))))))
>
> > Which works like a charm, with functional wrapper.The problem is in
> > the explicit call of eval.Performance issues right?So  is it possible
> > to somehow rewrite it as function without eval.
>
> Style issues actually.
> Yes, try (apply add-values values)
>
> and I'd still recommend looking at handler-bind.
>
> Sean.- Hide quoted text -
>
> - Show quoted text -

Thanks  for the pointer .
From: Kaz Kylheku
Subject: Re: ,@ with functions, *weird* macro behaviour
Date: 
Message-ID: <1181840796.171806.249980@d30g2000prg.googlegroups.com>
On Jun 14, 12:27 am, fireblade <·················@gmail.com> wrote:
> When I call the macro directly like :
> (1)
> (add-tuple #'authority-exist-p #'add-authority-values authority
> description))

This means that the VALUES variable inside the macro gets bound to the
list (#'ADD-AUTHORITY-VALUES AUTHORITY).  This list is turned into a
quoted literal which is inserted into the expansion.

This means that the #'ADD-AUTHORITY isn't actually a function object,
since it is not evaluated, but is simply the form (FUNCTION ADD-
AUTHORITY).

This is probably not what you want; you want the function itself,
right?

> But wrapped in a function makes a problem :
>
> (2)
> (defun add-authority (authority description)
>   (add-tuple #'authority-exist-p #'add-authority-values authority
> description))

AUTHORITY and DESCRIPTION end up in a quoted list, and so bear no
connection to the argument values that are passed to ADD-AUTHORITY.

> Wrapped in another macro like:
> (3)
> (defmacro add-authority (authority description)
>   `(add-tuple #'authority-exist-p #'add-authority-
> values ,authority ,description))
>
> and everything is fine again.

This is because thanks to the backquote, the outer macro will
substitute into the ADD-TUPLE call the original forms that are given
to it as its AUTHORITY and DESCRIPTION parameters.

This still won't work if these forms require evaluation, but it will
work if they are atoms that evaluate to themselves such as numbers or
strings.

But, for instance, suppose that you give (LIST 1 2) as the
DESCRIPTION. This means that the description will actually be (LIST 1
2) and not (1 2). That is to say, in the final macroexpansion, the
trailing arguments to the macro will be expanded using `,VALUES,
giving rise to a quoted list which contains (LIST 1 2) rather than (1
2).

> Which works like a charm, with functional wrapper.The problem is in
> the explicit call of eval.Performance issues right?

That's an unnecessary, trivial use of eval which can be replaced by
proper function application. Follow this rewrite rule:

 (eval `(funcall ,function ,@args)) ->  (apply function args)
From: fireblade
Subject: Re: ,@ with functions, *weird* macro behaviour
Date: 
Message-ID: <1181892494.021917.143320@k79g2000hse.googlegroups.com>
On Jun 14, 7:06 pm, Kaz Kylheku <········@gmail.com> wrote:
> On Jun 14, 12:27 am, fireblade <·················@gmail.com> wrote:
>
> > When I call the macro directly like :
> > (1)
> > (add-tuple #'authority-exist-p #'add-authority-values authority
> > description))
>
> This means that the VALUES variable inside the macro gets bound to the
> list (#'ADD-AUTHORITY-VALUES AUTHORITY).  This list is turned into a
> quoted literal which is inserted into the expansion.
>
> This means that the #'ADD-AUTHORITY isn't actually a function object,
> since it is not evaluated, but is simply the form (FUNCTION ADD-
> AUTHORITY).
>
> This is probably not what you want; you want the function itself,
> right?
>
> > But wrapped in a function makes a problem :
>
> > (2)
> > (defun add-authority (authority description)
> >   (add-tuple #'authority-exist-p #'add-authority-values authority
> > description))
>
> AUTHORITY and DESCRIPTION end up in a quoted list, and so bear no
> connection to the argument values that are passed to ADD-AUTHORITY.
>
> > Wrapped in another macro like:
> > (3)
> > (defmacro add-authority (authority description)
> >   `(add-tuple #'authority-exist-p #'add-authority-
> > values ,authority ,description))
>
> > and everything is fine again.
>
> This is because thanks to the backquote, the outer macro will
> substitute into the ADD-TUPLE call the original forms that are given
> to it as its AUTHORITY and DESCRIPTION parameters.
>
> This still won't work if these forms require evaluation, but it will
> work if they are atoms that evaluate to themselves such as numbers or
> strings.
>
> But, for instance, suppose that you give (LIST 1 2) as the
> DESCRIPTION. This means that the description will actually be (LIST 1
> 2) and not (1 2). That is to say, in the final macroexpansion, the
> trailing arguments to the macro will be expanded using `,VALUES,
> giving rise to a quoted list which contains (LIST 1 2) rather than (1
> 2).
>
> > Which works like a charm, with functional wrapper.The problem is in
> > the explicit call of eval.Performance issues right?
>
> That's an unnecessary, trivial use of eval which can be replaced by
> proper function application. Follow this rewrite rule:
>
>  (eval `(funcall ,function ,@args)) ->  (apply function args)

Thank you for the excellent reply to my confusing question I'll
proceed with a functional version of add-tuple , replacing eval with
apply,  I have a deadline to meet but later I'll study my macro a
little bit to see what makes it wrong. I didn't  put much thought as
you for forms requiring evaluation I only tested with atoms but  that
looks like a right way of doing things. Going through books and small
isolated examples is one thing , building a framework completely
another. One thing that makes me happy about lisp is that I learn new
things how to solve my problems, not  some low hacks how to bypass the
problem with fighting the language.


Slobodan Blazeski
From: Pascal Costanza
Subject: Re: ,@ with functions, *weird* macro behaviour
Date: 
Message-ID: <5dd9bkF34o126U2@mid.individual.net>
fireblade wrote:
> I have a macro that get's 2 functions (exist-p of 1 argument) and add-
> values (variable number of arguments)
> 
> (defmacro add-tuple (exist-p add-values &rest values)
>   `(multiple-value-bind (result error)
>       (ignore-errors
>         (funcall ,exist-p (car ',values)))
>     (cond ((typep error 'error)
>            (values
>             "Database error occured1"
>             t))
>           (result
>            (values
>             (string+  (car ',values) " exists.")
>             nil))
>           (t
>            (multiple-value-bind (result error)
>                (ignore-errors
>                  (funcall ,add-values ,@values))
>              (if (typep error 'error)
>                (values
>                 "database error occured2"
>                 t)
>                (values
>                 (string+  (car ',values) " inserted.")
>                 nil)))))))
> 
> When I call the macro directly like :
> (1)
> (add-tuple #'authority-exist-p #'add-authority-values authority
> description))
> 
> But wrapped in a function makes a problem :
> 
> (2)
> (defun add-authority (authority description)
>   (add-tuple #'authority-exist-p #'add-authority-values authority
> description))

You don't explain what the problem is, or what the expected result is 
and how the actual result deviates from the expected result. So it's 
hard to help you.

However, note that macroexpanding expression (1) shows that 'authority 
and 'description appear quoted in the resulting form. The variables 
passed to the function in (2) are not used in the resulting form. So I 
expect that you got the phases of macroexpansion time vs. runtime wrong. 
But I am just guessing here.


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/