Hi all,
First off an elementary question about Kawa Scheme: What functionality
corresponds with Common Lisp's macroexpand?
Consider this Common Lisp/Kawa Scheme macro:
(defmacro arg->list (arg) `(list ,arg))
In Common Lisp I can evaluate (let ((list 1)) (arg->list list)) and (1) is
returned. In Kawa Scheme the form evaluation breaks because I have rebound
the function `list.'
However at macro initialisation I could create a symbol with a pointer
to the list function:
(defmacro arg->list (arg) (let ((list-fn list)) `(,list-fn ,arg)))
Now (let ((list 1)) (arg->list list)) evaluates to (1). But I've replaced
one problem with a less likely one: The same issue will still arise if I
rebind `list-fn.'
So a solution at least as robust as the Common Lisp version appears to
require:
1. Binding a variable to a gensym (in Kawa Scheme one can use gentemp).
2. Binding the symbol value of the variable's uniquely generated symbol to
the function definition `list.'
3. Replacing the function position of the macro expansion with the
uniquely generated symbol.
I'm stuck on step 2. Is it possible to implement this more robust approach
in (Kawa) Scheme using defmacro?
Thanks,
Adam
Adam Warner <······@consulting.net.nz> writes:
> (defmacro arg->list (arg) (let ((list-fn list)) `(,list-fn ,arg)))
>
> Now (let ((list 1)) (arg->list list)) evaluates to (1). But I've replaced
> one problem with a less likely one: The same issue will still arise if I
> rebind `list-fn.'
Will it really? It seems to me that your macro is equivalent to:
(defmacro arg->list (arg)
`(,list ,arg))
Then, the form
(let ((list 1))
(arg->list list))
macroexpands to
(let ((list 1))
(#<subr list> list))
which AFAICT is not permitted by R5RS; but if Kawa allows it as
an extension, it would presumably call the original procedure
#<subr list> via the direct reference, regardless of how the
symbol has been bound in the meantime.
Hi Kalle Olavi Niemitalo,
> Adam Warner <······@consulting.net.nz> writes:
>
>> (defmacro arg->list (arg) (let ((list-fn list)) `(,list-fn ,arg)))
>>
>> Now (let ((list 1)) (arg->list list)) evaluates to (1). But I've replaced
>> one problem with a less likely one: The same issue will still arise if I
>> rebind `list-fn.'
>
> Will it really?
Thanks, of course the same issue doesn't arise!
> It seems to me that your macro is equivalent to:
>
> (defmacro arg->list (arg)
> `(,list ,arg))
So it seems!
> Then, the form
>
> (let ((list 1))
> (arg->list list))
>
> macroexpands to
>
> (let ((list 1))
> (#<subr list> list))
>
> which AFAICT is not permitted by R5RS; but if Kawa allows it as
> an extension, it would presumably call the original procedure
> #<subr list> via the direct reference, regardless of how the
> symbol has been bound in the meantime.
Indeed (I had accidentally mistyped a test form). I'd like to learn the
section of R5RS that makes this behaviour non-portable.
If this approach is permitted by a single namespace Lisp then defmacro is
just as straightforward to use as it is in Common Lisp!
Regards,
Adam
Adam Warner <······@consulting.net.nz> writes:
> I'd like to learn the section of R5RS that makes this behaviour
> non-portable.
The syntax for <literal> in 7.1.3 (Expressions) permits
procedures as neither <self-evaluating> nor <datum>. See also
4.1.2 (Literal expressions) and 3.3 (External representations).
Hi Kalle Olavi Niemitalo,
> The syntax for <literal> in 7.1.3 (Expressions) permits procedures as
> neither <self-evaluating> nor <datum>. See also 4.1.2 (Literal
> expressions) and 3.3 (External representations).
Is `(',list 123) likely to be any more portable? The procedure call
operator is now (quote #<procedure list>) which evaluates to the same
function as list evaluates to (this avoids self-evaluating the procedure
call operator).
Regards,
Adam
Adam Warner wrote:
> Hi Kalle Olavi Niemitalo,
>
>
>>It seems to me that your macro is equivalent to:
>>
>> (defmacro arg->list (arg)
>> `(,list ,arg))
[...]
> If this approach is permitted by a single namespace Lisp then defmacro is
> just as straightforward to use as it is in Common Lisp!
Not quite. Such a macro would capture the value of list's binding, not
the actual binding itself.
Pascal
--
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
Hi Pascal Costanza,
>>>It seems to me that your macro is equivalent to:
>>>
>>> (defmacro arg->list (arg)
>>> `(,list ,arg))
> [...]
>
>> If this approach is permitted by a single namespace Lisp then defmacro is
>> just as straightforward to use as it is in Common Lisp!
>
> Not quite. Such a macro would capture the value of list's binding, not
> the actual binding itself.
For completeness this avoids operator self-evaluation:
(defmacro arg->list (arg)
`(',list ,arg))
Pascal, could you explain the importance of the distinction you have
raised?
Thanks,
Adam
Adam Warner wrote:
> For completeness this avoids operator self-evaluation:
>
> (defmacro arg->list (arg)
> `(',list ,arg))
>
> Pascal, could you explain the importance of the distinction you have
> raised?
Here is an example with syntax-rules (in Scheme), in which the binding
is captured:
(define (test-fun x) x)
(define-syntax test
(syntax-rules ()
((_ x) (test-fun x))))
(define (test-call x)
(test x))
#;> (test-call 5)
5
#;> (set! test-fun list)
#;> (test-call 5)
(5)
Now the example with defmacro (in Common Lisp), in which the value of
the binding is captured:
(defun test-fun (x) x)
(defmacro test (x)
`(funcall ',#'test-fun ,x))
(defun test-call (x)
(test x))
? (test-call 5)
5
? (setf (symbol-function 'test-fun) (symbol-function 'list))
#<Compiled-function LIST #x20E11D6>
? (test-call 5)
5
The difference is that in the latter version the change to the function
test-fun is not seen.
For making use of functions in macros, this generally doesn't matter
much in Common Lisp. You would just say this...
(defmacro test (x)
`(test-fun ,x))
...and would get the same effect. Since the names of global functions
are significant elements of a program's ontology, it's extremely
unlikely that you accidentally capture them by local function
definitions. Global variables are usually special, so rebinding them
locally already has a special meaning that you need to be aware of.
Where the above may hurt you is in conjunction with local (lexically
scoped) variables:
? (let ((x 5))
(macrolet ((print-it ()
`(print x)))
(let ((x 10))
(print-it))))
10
The problem is: How do you access the outer x binding within the
print-it macro?
Pascal
--
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/