It might be easier just to do away with a special character
altogether and put a special function to return within the macro.
(defmacro prog-anywhere (&body body)
(let ((return-value (gensym)))
`(let ((,return-value nil))
(flet ((prog-return (value)
(setf ,return-value value)))
,@body)
,return-value)))
CL-USER 11 > (prog-anywhere
(if t
(1+ (prog-return 10))
(1- (prog-return 0))))
10
CL-USER 12 > (prog-anywhere
(if nil
(1+ (prog-return 10))
(1- (prog-return 0))))
0
CL-USER 13 >
The prog-anywhere can be renamed to anything one wants. I am
not sure how a VALUES return could be made to work. Also the
flet could be replaced with a macrolet if one is concerned
with generating anonymous functions all over the place.
Wade
This can be even simpler and work in calls down the stack.
(defvar *prog-anywhere-return* nil)
(defun prog-return (value) (setf *prog-anywhere-return* value))
(defmacro prog-anywhere (&body body)
`(progn
,@body
*prog-anywhere-return*))
Wade
In article <·····················@news1.telusplanet.net>,
Wade Humeniuk <····@nospam.nowhere> wrote:
>
>This can be even simpler and work in calls down the stack.
>
>(defvar *prog-anywhere-return* nil)
>
>(defun prog-return (value) (setf *prog-anywhere-return* value))
>
>(defmacro prog-anywhere (&body body)
> `(progn
> ,@body
> *prog-anywhere-return*))
Your previous version, with the FLET, addressed my issue of nesting these
things.
Using a global variable like this is actually worse than the OP's version.
Not only can't they nest lexically, they also can't nest dynamically.
E.g. the following won't work right:
(defun fun1 ()
(prog-anywhere
@ 'fun1
(fun2)))
(defun fun2 ()
(prog-anywhere
@ 'fun2))
(fun1) should return FUN1, but it will return FUN2. This is the type of
referential transparency problem that lexical scoping was designed to
solve.
--
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
"Barry Margolin" <······@genuity.net> wrote in message
······················@paloalto-snr1.gtei.net...
> Your previous version, with the FLET, addressed my issue of nesting these
> things.
>
> Using a global variable like this is actually worse than the OP's version.
> Not only can't they nest lexically, they also can't nest dynamically.
> E.g. the following won't work right:
>
> (defun fun1 ()
> (prog-anywhere
> @ 'fun1
> (fun2)))
>
> (defun fun2 ()
> (prog-anywhere
> @ 'fun2))
>
> (fun1) should return FUN1, but it will return FUN2. This is the type of
> referential transparency problem that lexical scoping was designed to
> solve.
Oops, I guess that should be
(defvar *prog-anywhere-return* nil)
(defun prog-return (value) (setf *prog-anywhere-return* value))
(defmacro prog-anywhere (&body body)
`(let (*prog-anywhere-return*)
,@body
*prog-anywhere-return*))
CL-USER 3 > (defun fun2 ()
(prog-anywhere
(prog-return 'fun2)))
FUN2
CL-USER 4 > (defun fun1 ()
(prog-anywhere
(prog-return 'fun1)
(fun2)))
FUN1
CL-USER 5 > (fun1)
FUN1
CL-USER 6 >
Wade
* "Wade Humeniuk" <····@nospam.nowhere>
| This can be even simpler and work in calls down the stack.
|
| (defvar *prog-anywhere-return* nil)
|
| (defun prog-return (value) (setf *prog-anywhere-return* value))
|
| (defmacro prog-anywhere (&body body)
| `(progn
| ,@body
| *prog-anywhere-return*))
Make that
(defmacro prog-anywhere (&body body)
`(let (*prog-anywhere-return*)
,@body
*prog-anywhere-return*))
--
Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
"Wade Humeniuk" <····@nospam.nowhere> writes:
> The prog-anywhere can be renamed to anything one wants. I am
> not sure how a VALUES return could be made to work. Also the
> flet could be replaced with a macrolet if one is concerned
> with generating anonymous functions all over the place.
Here's something along these lines that would allow multiple
values:
(defmacro prog-anywhere (returner-name &body body)
(let ((return-values-list (gensym "RETURN-VALUES-LIST")))
`(let (,return-values-list)
(flet ((,returner-name (&rest values)
(setf ,return-values-list values)))
,@body
(values-list ,return-values-list)))))
* (prog-anywhere return-outer
(multiple-value-bind (a b)
(prog-anywhere return-inner
1
(return-inner 2 3)
4
(return-outer 5 6)
7)
(print (cons a b))))
(2 . 3)
5
6
*
Gabe Garza
"Gabe Garza" <·······@ix.netcom.com> wrote in message ···················@ix.netcom.com...
> (defmacro prog-anywhere (returner-name &body body)
> (let ((return-values-list (gensym "RETURN-VALUES-LIST")))
> `(let (,return-values-list)
> (flet ((,returner-name (&rest values)
> (setf ,return-values-list values)))
> ,@body
> (values-list ,return-values-list)))))
>
> * (prog-anywhere return-outer
> (multiple-value-bind (a b)
> (prog-anywhere return-inner
> 1
> (return-inner 2 3)
> 4
> (return-outer 5 6)
> 7)
> (print (cons a b))))
> (2 . 3)
> 5
> 6
> *
Nice touch with the returner-name. I get that mind altered feeling
with the example. It feels like it would be useful in real life (a kind of
a space connected with a whole bunch of wormholes), though I am
don't know where. Adds a new take on the idea of spaghetti code.
Wade
Gabe Garza wrote:
> "Wade Humeniuk" <····@nospam.nowhere> writes:
>
>
>>The prog-anywhere can be renamed to anything one wants. I am
>>not sure how a VALUES return could be made to work. Also the
>>flet could be replaced with a macrolet if one is concerned
>>with generating anonymous functions all over the place.
>
>
> Here's something along these lines that would allow multiple
> values:
>
> (defmacro prog-anywhere (returner-name &body body)
> (let ((return-values-list (gensym "RETURN-VALUES-LIST")))
> `(let (,return-values-list)
> (flet ((,returner-name (&rest values)
> (setf ,return-values-list values)))
> ,@body
> (values-list ,return-values-list)))))
Yes, but the following still doesn't work.
> (prog-anywhere !
5 6 7
(! (values 42 43 44))
8 9 10)
42
To be able to deal with multiple values is especially important when you
want to call a (predefined) function that returns multiple values.
Another question: I have seen (gensym "SOME-NAME") every now and then.
My understanding of this usage of gensym is that the generated symbols
aren't strictly unique anymore, right? Why do people still use this idiom?
Pascal
--
Given any rule, however �fundamental� or �necessary� for science, there
are always circumstances when it is advisable not only to ignore the
rule, but to adopt its opposite. - Paul Feyerabend
Pascal Costanza <········@web.de> writes:
> Yes, but the following still doesn't work.
>
> > (prog-anywhere !
> 5 6 7
> (! (values 42 43 44))
> 8 9 10)
> 42
>
> To be able to deal with multiple values is especially important when
> you want to call a (predefined) function that returns multiple values.
If that's the semantics you want you could always use:
(defmacro multiple-value-prog-anywhere (returner-name &body body)
(let ((return-values-list (gensym "RETURN-VALUES-LIST")))
`(let (,return-values-list)
(macrolet ((,returner-name (&body body)
`(setf ,',return-values-list
(multiple-value-list ,@body))))
,@body
(values-list ,return-values-list)))))
* (multiple-value-prog-anywhere !
5 6 7
(! (values 42 43 44))
8 9 10)
42
43
44
*
> Another question: I have seen (gensym "SOME-NAME") every now and
> then. My understanding of this usage of gensym is that the generated
> symbols aren't strictly unique anymore, right? Why do people still use
> this idiom?
The generated symbols are unique--that's the whole point of gensym. I
assume you're confused over giving it a name...
In this case, I used it for ease of debugging. Any worthy Common Lisp
environment will have a facility for macroexpanding a form so you can
see what your macros are expanding to. For example, in ilisp if I put
the cursor before the previous example and type M-x macroexpand-lisp
the following output is displayed:
(LET (#:RETURN-VALUES-LIST2158)
(MACROLET ((! (&BODY BODY)
`(SETF #:RETURN-VALUES-LIST2158 (MULTIPLE-VALUE-LIST ,@BODY))))
5
6
7
(! (VALUES 42 43 44))
8
9
10
(VALUES-LIST #:RETURN-VALUES-LIST2158)))
In this case, it's not that necessary. But in more complicated
macros, or nested macros, etc., it can be.
Gabe Garza
Pascal Costanza <········@web.de> writes:
> Yes, but the following still doesn't work.
>
> > (prog-anywhere !
> 5 6 7
> (! (values 42 43 44))
> 8 9 10)
> 42
>
> To be able to deal with multiple values is especially important when
> you want to call a (predefined) function that returns multiple values.
If that's the semantics you want you could always use:
(defmacro multiple-value-prog-anywhere (returner-name &body body)
(let ((return-values-list (gensym "RETURN-VALUES-LIST")))
`(let (,return-values-list)
(macrolet ((,returner-name (form)
`(setf ,',return-values-list
(multiple-value-list ,form))))
,@body
(values-list ,return-values-list)))))
* (multiple-value-prog-anywhere !
5 6 7
(! (values 42 43 44))
8 9 10)
42
43
44
*
> Another question: I have seen (gensym "SOME-NAME") every now and
> then. My understanding of this usage of gensym is that the generated
> symbols aren't strictly unique anymore, right? Why do people still use
> this idiom?
The generated symbols are unique--that's the whole point of gensym. I
assume you're confused over giving it a name...
In this case, I used it for ease of debugging. Any worthy Common Lisp
environment will have a facility for macroexpanding a form so you can
see what your macros are expanding to. For example, in ilisp if I put
the cursor before the previous example and type M-x macroexpand-lisp
the following output is displayed:
(LET (#:RETURN-VALUES-LIST2158)
(MACROLET ((! (&BODY BODY)
`(SETF #:RETURN-VALUES-LIST2158 (MULTIPLE-VALUE-LIST ,@BODY))))
5
6
7
(! (VALUES 42 43 44))
8
9
10
(VALUES-LIST #:RETURN-VALUES-LIST2158)))
In this case, it's not that necessary. But in more complicated
macros, or nested macros, etc., it can be.
Gabe Garza
Gabe Garza wrote:
> Pascal Costanza <········@web.de> writes:
>
>>Another question: I have seen (gensym "SOME-NAME") every now and
>>then. My understanding of this usage of gensym is that the generated
>>symbols aren't strictly unique anymore, right? Why do people still use
>>this idiom?
>
>
> The generated symbols are unique--that's the whole point of gensym. I
> assume you're confused over giving it a name...
>
No, it's about the uniqueness. In the example you have given, it may be
the case that RETURN-VALUES-LIST2158 has already existed before. As far
as I understand the HyperSpec a Common Lisp implementation is not
required to take the necessary precautions against this case (whereas
(gensym) without a string argument is always guaranteed to be unique).
Right?
> (LET (#:RETURN-VALUES-LIST2158)
> (MACROLET ((! (&BODY BODY)
> `(SETF #:RETURN-VALUES-LIST2158 (MULTIPLE-VALUE-LIST ,@BODY))))
> 5
> 6
> 7
> (! (VALUES 42 43 44))
> 8
> 9
> 10
> (VALUES-LIST #:RETURN-VALUES-LIST2158)))
Pascal
--
Given any rule, however �fundamental� or �necessary� for science, there
are always circumstances when it is advisable not only to ignore the
rule, but to adopt its opposite. - Paul Feyerabend
Pascal Costanza <········@web.de> writes:
> Gabe Garza wrote:
> > Pascal Costanza <········@web.de> writes:
> >
>
> >>Another question: I have seen (gensym "SOME-NAME") every now and
> >>then. My understanding of this usage of gensym is that the generated
> >>symbols aren't strictly unique anymore, right? Why do people still use
> >>this idiom?
> > The generated symbols are unique--that's the whole point of gensym.
> > I
> > assume you're confused over giving it a name...
> >
>
> No, it's about the uniqueness. In the example you have given, it may
> be the case that RETURN-VALUES-LIST2158 has already existed before. As
> far as I understand the HyperSpec a Common Lisp implementation is not
> required to take the necessary precautions against this case (whereas
> (gensym) without a string argument is always guaranteed to be
> unique). Right?
Wrong.
A symbol with the name RETURN-VALUES-LIST2158 may already have
existed; however, it is a different symbol from the one returned by
gensym. The CLHS page on gensym makes this clear, when it says that
the return value is a "fresh, uninterned symbol".
* '#:foo-1 -> #:FOO-1
* (setf *gensym-counter* 1) -> 1
* (gensym "FOO-") -> #:FOO-1
* (eq * ***) -> NIL
Cheers,
Christophe
--
http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge)
Christophe Rhodes wrote:
> Pascal Costanza <········@web.de> writes:
>
>
>>Gabe Garza wrote:
>>
>>>Pascal Costanza <········@web.de> writes:
>>>
>>
>>>>Another question: I have seen (gensym "SOME-NAME") every now and
>>>>then. My understanding of this usage of gensym is that the generated
>>>>symbols aren't strictly unique anymore, right? Why do people still use
>>>>this idiom?
>>>
>>>The generated symbols are unique--that's the whole point of gensym.
>>>I
>>>assume you're confused over giving it a name...
>>>
>>
>>No, it's about the uniqueness. In the example you have given, it may
>>be the case that RETURN-VALUES-LIST2158 has already existed before. As
>>far as I understand the HyperSpec a Common Lisp implementation is not
>>required to take the necessary precautions against this case (whereas
>>(gensym) without a string argument is always guaranteed to be
>>unique). Right?
>
>
> Wrong.
>
> A symbol with the name RETURN-VALUES-LIST2158 may already have
> existed; however, it is a different symbol from the one returned by
> gensym. The CLHS page on gensym makes this clear, when it says that
> the return value is a "fresh, uninterned symbol".
>
> * '#:foo-1 -> #:FOO-1
> * (setf *gensym-counter* 1) -> 1
> * (gensym "FOO-") -> #:FOO-1
> * (eq * ***) -> NIL
Now I am really confused. How does a macro treat uninterned symbols, how
are they evaluated.
I have tried the following.
(defmacro test ()
(let ((bla #:bla))
`(let ((,bla '(1 2 3))
(pprint ,bla))))
> (test)
(1 2 3)
> (macroexpand +)
(LET ((#:BLA (QUOTE (1 2 3)))) (PPRINT #:BLA))
> (LET ((#:BLA (QUOTE (1 2 3)))) (PPRINT #:BLA))
Error: The variable #:BLA is unbound.
Huh?!? Of course, #:BLA is an uninterned symbol, but why does the macro
'test work in the first place?
Then again:
(defmacro test ()
`(let ((#:BLA '(1 2 3)))
(pprint #:BLA)))
> (test)
Error: The variable #:BLA is unbound.
?!?
I have tried to find a clue in the HyperSpec sections about macros,
symbols, evaluation, backquote and even packages, but I haven't found an
explanation. So basically I am stuck. What's going on here?
Pascal
--
Pascal Costanza University of Bonn
···············@web.de Institute of Computer Science III
http://www.pascalcostanza.de R�merstr. 164, D-53117 Bonn (Germany)
Pascal Costanza <········@web.de> writes:
> Christophe Rhodes wrote:
> > Pascal Costanza <········@web.de> writes:
> >>No, it's about the uniqueness. In the example you have given, it may
> >>be the case that RETURN-VALUES-LIST2158 has already existed before. As
> >>far as I understand the HyperSpec a Common Lisp implementation is not
> >>required to take the necessary precautions against this case (whereas
> >>(gensym) without a string argument is always guaranteed to be
> >>unique). Right?
> > Wrong.
> > A symbol with the name RETURN-VALUES-LIST2158 may already have
> > existed; however, it is a different symbol from the one returned by
> > gensym. The CLHS page on gensym makes this clear, when it says that
> > the return value is a "fresh, uninterned symbol".
> > * '#:foo-1 -> #:FOO-1
> > * (setf *gensym-counter* 1) -> 1
> > * (gensym "FOO-") -> #:FOO-1
> > * (eq * ***) -> NIL
>
> Now I am really confused. How does a macro treat uninterned symbols,
> how are they evaluated.
>
> I have tried the following.
>
> (defmacro test ()
> (let ((bla #:bla))
> `(let ((,bla '(1 2 3))
> (pprint ,bla))))
>
> > (test)
> (1 2 3)
>
> > (macroexpand +)
> (LET ((#:BLA (QUOTE (1 2 3)))) (PPRINT #:BLA))
Hmm. Rewriting for the sake of posterity:
(defmacro test ()
(let ((bla '#:bla))
`(let ((,bla '(1 2 3)))
(pprint ,bla))))
Then
(macroexpand '(test))
gives
(LET ((#:BLA '(1 2 3)))
(PPRINT #:BLA))
So, why does this not work when typed in? Well, think about object
identity. In the macroexpansion, the two things that have printed as
#:BLA are the same symbol; if you type this in, you get two different
uninterned symbols with the name "BLA". To see this:
(setf *print-circle* t)
(macroexpand '(test))
gives
(LET ((#1=#:BLA '(1 2 3)))
(PPRINT #1#))
Two different symbols can have the same name, and can print the same.
Christophe
--
http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge)
Christophe Rhodes wrote:
> Pascal Costanza <········@web.de> writes:
>>Now I am really confused. How does a macro treat uninterned symbols,
>>how are they evaluated.
>>
>
>
> Hmm. Rewriting for the sake of posterity:
> (defmacro test ()
> (let ((bla '#:bla))
> `(let ((,bla '(1 2 3)))
> (pprint ,bla))))
Er, yes, that's what I meant.
> Then
> (macroexpand '(test))
> gives
> (LET ((#:BLA '(1 2 3)))
> (PPRINT #:BLA))
> So, why does this not work when typed in? Well, think about object
> identity. In the macroexpansion, the two things that have printed as
> #:BLA are the same symbol; if you type this in, you get two different
> uninterned symbols with the name "BLA".
Oh dear - yes, that's clear as daylight! Now I also understand why
(gensym "SOME-NAME") is safe.
Thanks a lot indeed!
Pascal
--
Pascal Costanza University of Bonn
···············@web.de Institute of Computer Science III
http://www.pascalcostanza.de R�merstr. 164, D-53117 Bonn (Germany)
Pascal Costanza <········@web.de> writes:
> Now I am really confused. How does a macro treat uninterned symbols,
> how are they evaluated.
Just like any other symbols. It is mostly the reader and printer that
deals specially with uninterned symbols:
(eq '#:foo '#:foo) => NIL
--
Frode Vatvedt Fjeld