From: Sebastian Tennant on
Hi all,

I don't really understand why this is:

CL-USER> (defmacro foo (pair)
(funcall (car pair) (cadr pair)))
FOO
CL-USER> (defun bar (arg) arg)
BAR
CL-USER> (foo (bar "baz"))
"baz"
CL-USER> (let ((baz (lambda (arg) arg)))
(foo (baz "quux")))
; in: LAMBDA NIL
; (FOO (BAZ "quux"))
;
; caught ERROR:
; (in macroexpansion of (FOO (BAZ "quux")))
; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
; The function BAZ is undefined.

; (LET ((BAZ (LAMBDA (ARG) ARG)))
; (FOO (BAZ "quux")))
;
; caught STYLE-WARNING:
; The variable BAZ is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 1 STYLE-WARNING condition
Execution of a form compiled with errors.

I understand that macro arguments aren't evaluated, i.e., that they manipulate
s-expressions, not runtime values, but does this really mean there is no way of
using an anonymous function in a macro?

I'd have thought binding baz to the anonymous function beforehand would get
around the above restrictions.

Any hints or explanations much appreciated.

Seb
--
Emacs' AlsaPlayer - Music Without Jolts
Lightweight, full-featured and mindful of your idyllic happiness.
http://home.gna.org/eap
From: refun on
In article <sk8njv6w.fsf(a)vps203.linuxvps.org>, sebyte(a)smolny.plus.com says...
>
> Hi all,
>
> I don't really understand why this is:
>
> CL-USER> (defmacro foo (pair)
> (funcall (car pair) (cadr pair)))
> FOO
> CL-USER> (defun bar (arg) arg)
> BAR
> CL-USER> (foo (bar "baz"))
> "baz"
> CL-USER> (let ((baz (lambda (arg) arg)))
> (foo (baz "quux")))
> ; in: LAMBDA NIL
> ; (FOO (BAZ "quux"))
> ;
> ; caught ERROR:
> ; (in macroexpansion of (FOO (BAZ "quux")))
> ; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
> ; The function BAZ is undefined.
>
> ; (LET ((BAZ (LAMBDA (ARG) ARG)))
> ; (FOO (BAZ "quux")))
> ;
> ; caught STYLE-WARNING:
> ; The variable BAZ is defined but never used.
> ;
> ; compilation unit finished
> ; caught 1 ERROR condition
> ; caught 1 STYLE-WARNING condition
> Execution of a form compiled with errors.
>
> I understand that macro arguments aren't evaluated, i.e., that they manipulate
> s-expressions, not runtime values, but does this really mean there is no way of
> using an anonymous function in a macro?
>
> I'd have thought binding baz to the anonymous function beforehand would get
> around the above restrictions.
>
> Any hints or explanations much appreciated.
>
> Seb

I'm a bit confused about what you want to do.

Your FOO macro attempts to FUNCALL the car of your pair argument at COMPILE-
time. While this is possible, it's usually a bad idea, as you may be causing
side-effects at compile-time. Macros should usually be used as functional (non-
side-effecting) code transformations. So you could for example write something
like:
(defmacro foo (&body body) `(funcall ,@body))
and have FOO expand into a FUNCALL.
(foo (lambda (x) (1+ x)) 9)
expands to
(FUNCALL (LAMBDA (X) (1+ X)) 9)
which evaluates to 10.
(foo #'bar "baz") ;=> "baz"
(flet ((baz (x) x)) (foo #'baz "quux")) ;=> "quux"

I don't see much practical purpose for this, except to define synonyms to
functions, but this is far from a an ideal way to do it.

Can you elaborate on what exactly is it that you want to do?
From: Pascal J. Bourguignon on
Sebastian Tennant <sebyte(a)smolny.plus.com> writes:

> Hi all,
>
> I don't really understand why this is:
>
> CL-USER> (defmacro foo (pair)
> (funcall (car pair) (cadr pair)))
> FOO
> CL-USER> (defun bar (arg) arg)
> BAR
> CL-USER> (foo (bar "baz"))
> "baz"

Notice that:

C/USER[11]> (macroexpand '(foo (bar "baz")))
"baz" ;
T

That is, the call to BAR is made at macro-expansion time.
If the function BAR had not be defined at the REPL, but in a file, it
wouldn't be defined at compilation time, and therefore not at
macro-expansion time, and the execution of the macro FOO would have
failed.

Also, macroexpansion may occur several time, and therefore the function
BAR may be called several times.

On the other hand, the expansion is "baz" itself, therefore once the
macro FOO is expanded, the function BAR is never called at run-time.


> CL-USER> (let ((baz (lambda (arg) arg)))
> (foo (baz "quux")))
> ; in: LAMBDA NIL
> ; (FOO (BAZ "quux"))
> ;
> ; caught ERROR:
> ; (in macroexpansion of (FOO (BAZ "quux")))
> ; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
> ; The function BAZ is undefined.
>
> ; (LET ((BAZ (LAMBDA (ARG) ARG)))
> ; (FOO (BAZ "quux")))
> ;
> ; caught STYLE-WARNING:
> ; The variable BAZ is defined but never used.
> ;
> ; compilation unit finished
> ; caught 1 ERROR condition
> ; caught 1 STYLE-WARNING condition
> Execution of a form compiled with errors.
>
> I understand that macro arguments aren't evaluated, i.e., that they manipulate
> s-expressions, not runtime values, but does this really mean there is no way of
> using an anonymous function in a macro?

Read again the error message!

> ; The function BAZ is undefined.


And read again the warning!

> ; The variable BAZ is defined but never used.


You cannot say that clisp doesn't try all it can to tell you there's a
problem with BAZ...

The problem is that BAZ is a lexical variable, and even when the LET
form is typed at the REPL, lexical variables don't exist during
macroexpansion. This has nothing to do with the fact that it will
eventually be bound to an anonymous function, but just with the fact
that it will be bound LATER.


> I'd have thought binding baz to the anonymous function beforehand would get
> around the above restrictions.

You're wrong, it's not bound beforehand.

1- a form is read.

2- a form is compiled.
2.1- a form is macroexpanded (during minimal compilation)
2.2- the code for the form is generated.

3- a form is executed
3.1- a LET form binds variables.
....




> Any hints or explanations much appreciated.

Your macro is wrong and senseless.

What do you want to archieve?


--
__Pascal Bourguignon__
From: Ron Garret on
In article <sk8njv6w.fsf(a)vps203.linuxvps.org>,
Sebastian Tennant <sebyte(a)smolny.plus.com> wrote:

> Hi all,
>
> I don't really understand why this is:
>
> CL-USER> (defmacro foo (pair)
> (funcall (car pair) (cadr pair)))
> FOO
> CL-USER> (defun bar (arg) arg)
> BAR
> CL-USER> (foo (bar "baz"))
> "baz"
> CL-USER> (let ((baz (lambda (arg) arg)))
> (foo (baz "quux")))
> ; in: LAMBDA NIL
> ; (FOO (BAZ "quux"))
> ;
> ; caught ERROR:
> ; (in macroexpansion of (FOO (BAZ "quux")))
> ; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
> ; The function BAZ is undefined.
>
> ; (LET ((BAZ (LAMBDA (ARG) ARG)))
> ; (FOO (BAZ "quux")))
> ;
> ; caught STYLE-WARNING:
> ; The variable BAZ is defined but never used.
> ;
> ; compilation unit finished
> ; caught 1 ERROR condition
> ; caught 1 STYLE-WARNING condition
> Execution of a form compiled with errors.
>
> I understand that macro arguments aren't evaluated, i.e., that they
> manipulate s-expressions, not runtime values,

You apparently do not understand this because in your example the
anonymous function to which BAZ is bound, and which you are trying to
invoke in your expansion of FOO, is a run-time value.

(BTW, you should not feel bad about not understanding this. It's a very
tricky and subtle issue.)

> but does this really mean there is no way of
> using an anonymous function in a macro?

No, it does not mean that. It doesn't even mean that there is no way to
use an anonymous function created at run-time (which is not the same
thing, but which is what you are actually doing in your example) in a
macro. But it is tricky.

> I'd have thought binding baz to the anonymous function beforehand would get
> around the above restrictions.
>
> Any hints or explanations much appreciated.

You have to achieve clarity about the order in which various things
happen, and in particular, when BAZ is bound, and when FOO is expanded.
In your example above, FOO expanded *before* BAZ is bound, which is why
you get the error you do.

Figuring out how to make this work is non-trivial. The real answer can
be found here:

http://p-cos.net/documents/hygiene.pdf

But if you find that paper impenetrable and you are interested in
pursuing this let me know. It's on my agenda to write a more gently
introduction to this issue, and if I knew someone was interested that
would be motivation to bump it up in the queue.

rg
From: Sebastian Tennant on
Many thanks to all respondents. Some very clear and helpful
explanations, shedding light on the considerable gaps in my
understanding.

Ron, I'd definitely like to read your treatment on the issue. Your
Complete Idiot's Guide to Common Lisp Packages was very illuminating.

Regards,

Sebastian