Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.lisp > #32931 > unrolled thread
| Started by | Stefan Monnier <monnier@iro.umontreal.ca> |
|---|---|
| First post | 2019-05-21 15:46 -0400 |
| Last post | 2019-05-22 18:47 -0700 |
| Articles | 20 on this page of 22 — 7 participants |
Back to article view | Back to comp.lang.lisp
symbol-macros -vs- symbol setf-expander Stefan Monnier <monnier@iro.umontreal.ca> - 2019-05-21 15:46 -0400
Re: symbol-macros -vs- symbol setf-expander Kaz Kylheku <847-115-0292@kylheku.com> - 2019-05-21 21:25 +0000
Re: symbol-macros -vs- symbol setf-expander Kaz Kylheku <847-115-0292@kylheku.com> - 2019-05-22 20:07 +0000
Re: symbol-macros -vs- symbol setf-expander Stefan Monnier <monnier@iro.umontreal.ca> - 2019-05-30 15:40 -0400
Re: symbol-macros -vs- symbol setf-expander Kaz Kylheku <847-115-0292@kylheku.com> - 2019-05-31 04:51 +0000
Re: symbol-macros -vs- symbol setf-expander "Pascal J. Bourguignon" <pjb@informatimago.com> - 2019-05-31 16:38 +0200
Re: symbol-macros -vs- symbol setf-expander Kaz Kylheku <847-115-0292@kylheku.com> - 2019-05-31 18:42 +0000
Re: symbol-macros -vs- symbol setf-expander "Pascal J. Bourguignon" <pjb@informatimago.com> - 2019-05-31 21:24 +0200
Re: symbol-macros -vs- symbol setf-expander Kaz Kylheku <847-115-0292@kylheku.com> - 2019-06-01 02:34 +0000
Re: symbol-macros -vs- symbol setf-expander Stefan Monnier <monnier@iro.umontreal.ca> - 2019-05-31 18:14 -0400
Re: symbol-macros -vs- symbol setf-expander Kaz Kylheku <847-115-0292@kylheku.com> - 2019-06-01 02:51 +0000
Re: symbol-macros -vs- symbol setf-expander Stefan Monnier <monnier@iro.umontreal.ca> - 2019-06-02 12:16 -0400
Re: symbol-macros -vs- symbol setf-expander Kaz Kylheku <847-115-0292@kylheku.com> - 2019-06-03 01:13 +0000
Re: symbol-macros -vs- symbol setf-expander Stefan Monnier <monnier@iro.umontreal.ca> - 2019-05-31 18:04 -0400
Re: symbol-macros -vs- symbol setf-expander "Pascal J. Bourguignon" <pjb@informatimago.com> - 2019-05-22 22:00 +0200
Re: symbol-macros -vs- symbol setf-expander a.daniel.eliason@gmail.com - 2019-05-23 08:10 -0700
Re: symbol-macros -vs- symbol setf-expander Spiros Bousbouras <spibou@gmail.com> - 2019-05-23 15:22 +0000
Re: symbol-macros -vs- symbol setf-expander Dimitri Fontaine <dim@tapoueh.org> - 2019-05-23 18:02 +0200
Re: symbol-macros -vs- symbol setf-expander Spiros Bousbouras <spibou@gmail.com> - 2019-05-23 16:51 +0000
Re: symbol-macros -vs- symbol setf-expander Kaz Kylheku <847-115-0292@kylheku.com> - 2019-05-23 17:05 +0000
Re: symbol-macros -vs- symbol setf-expander "Pascal J. Bourguignon" <pjb@informatimago.com> - 2019-05-23 19:26 +0200
Re: symbol-macros -vs- symbol setf-expander smh <shaflich@gmail.com> - 2019-05-22 18:47 -0700
Page 1 of 2 [1] 2 Next page →
| From | Stefan Monnier <monnier@iro.umontreal.ca> |
|---|---|
| Date | 2019-05-21 15:46 -0400 |
| Subject | symbol-macros -vs- symbol setf-expander |
| Message-ID | <jwv5zq3eh4i.fsf-monnier+comp.lang.lisp@gnu.org> |
While discussing some extension to Elisp's `gv`, someone pointed out
that symbol-macros basically allow you to define a symbol as an
arbitrary "place", i.e. a kind of "place alias".
Yet, it's subtly different since
(symbol-macrolet ((x (nth 5 (get-list)))) ...)
will re-execute (get-list) (and `nthcdr 5`) everytime `x` is used
without offering any easy way to take advantage of the setf-expander
infrastructure's ability to do those computations only once.
Does anyone here know of work related to this, e.g. discussions about
the detailed semantics of symbol-macrolet?
Stefan
[toc] | [next] | [standalone]
| From | Kaz Kylheku <847-115-0292@kylheku.com> |
|---|---|
| Date | 2019-05-21 21:25 +0000 |
| Message-ID | <20190521125844.749@kylheku.com> |
| In reply to | #32931 |
On 2019-05-21, Stefan Monnier <monnier@iro.umontreal.ca> wrote:
> While discussing some extension to Elisp's `gv`, someone pointed out
> that symbol-macros basically allow you to define a symbol as an
> arbitrary "place", i.e. a kind of "place alias".
>
> Yet, it's subtly different since
>
> (symbol-macrolet ((x (nth 5 (get-list)))) ...)
>
> will re-execute (get-list) (and `nthcdr 5`) everytime `x` is used
> without offering any easy way to take advantage of the setf-expander
> infrastructure's ability to do those computations only once.
>
> Does anyone here know of work related to this, e.g. discussions about
> the detailed semantics of symbol-macrolet?
We have probably discussed this before, but in TXR Lisp I provide
something called placelet.
Placelet lexically binds symbols nicknames to places (similarly to
symbol macros), but with once-only semantics.
Ten second demo:
1> (expand '(placelet ((x (nth 5 (get-list))))
(list x x (inc x))))
(let ((#:g0011 (nthcdr 5 (get-list))))
(list (car #:g0011)
(car #:g0011)
(sys:rplaca #:g0011 (succ (car #:g0011)))))
Doc: http://nongnu.org/txr/txr-manpage.html#N-0393C970
Implementation: http://www.kylheku.com/cgit/txr/tree/share/txr/stdlib/place.tl
The bulk of the logic is in a macro called sys:placelet-1.
symbol-macrolet (called symacrolet) plays a key role, as do multiple
occurrences of macrolet; placelet isn't symacrolet, but its implementation
depends on it.
How the implementation works is that during expansion, placelet will
dynamically insert place definitions into the global hash table,
and then remove them (via unwind-protect).
The symbol in question, like in this case x, is then macro-replaced
with references to the temporary place.
The details are little tricky. The definitions use gensyms, so for instance
a place resembling (#:g0025) is defined whose "getter" might be
a form like (#:g0009) and whose setter is (#:g0010 <new-value>).
This #:g0025 is held in the tmp-place variable in sys:placelet-1
implementation.
The code is generated to instantiate the original (nth 5 ...) place.
The #:g0011 gensym is bound to (nthcdr 5 (get-list)). Together with this,
local macros are provided using gensym-ed names, so that the macrolet (#:g0009)
expands to the access (car #:g0011), and the macrolet form (#:g0010 whatever)
expands to (sys:rplaca #:g0011 whatever). These are the tmp-getter and
tmp-setter gensyms in sys:placelet-1.
The symbol x is then forcibly replaced with (#:g0025) throughout the code body
(full expand pass). At that stage the code fragments then looks like:
(let ((#:g0011 (nthcdr 5 (get-list))))
(macrolet ((#:g0009 () (car #:g0011)))
(#:g0010 (val) (sys:rplaca #:g0011 val)))
;; tenative inner fragment: not finished yet:
(list (#:g0025) (#:g0025) (sys:rplaca #:g0011 (succ (car #:g0011)))))
We can see that the simple accesses to x are replaced by just (#:g0025),
the form denoting the temporary place. But where this is (#:g0025) is actually
used as a place, in the (inc ...) form, it is processed all the way to
(sys:rplaca #:g0011 ...) thanks to the workings of the temporary registration
of the (#:g0025) alias place.
Why (#:g0025) didn't get expanded into anything is that we have not defined
such a function or macro; we have (dynamically/locally) defined the place
(#:g0025) only, but for a fictitious form (#:g0025) that has no binding.
So now we are introducing that binding: we map (#:0025) to the access macrolet
(#:g0009):
(macrolet ((#:g0025 (#:g0009))) ...)
Ending up with:
(let ((#:g0011 (nthcdr 5 (get-list))))
(macrolet ((#:g0009 () (car #:g0011))) ;; <---- #:g0009 is here!
(#:g0010 (val) (sys:rplaca #:g0011 val)))
(macrolet ((#:g0025 (#:g0009))) ;; <--- referenced from here!
(list (#:g0025) (#:g0025) (sys:rplaca #:g0011 (succ (car #:g0011))))))
This inner macrolet shakes out the (#:g0025) forms, replacing them with
(#:g0009) which immediately goes to the (car #:g0011) access form,
thanks to the outer macrolet.
--
TXR Programming Lanuage: http://nongnu.org/txr
Music DIY Mailing List: http://www.kylheku.com/diy
ADA MP-1 Mailing List: http://www.kylheku.com/mp1
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <847-115-0292@kylheku.com> |
|---|---|
| Date | 2019-05-22 20:07 +0000 |
| Message-ID | <20190522125932.721@kylheku.com> |
| In reply to | #32932 |
On 2019-05-21, Kaz Kylheku <847-115-0292@kylheku.com> wrote: > On 2019-05-21, Stefan Monnier <monnier@iro.umontreal.ca> wrote: >> While discussing some extension to Elisp's `gv`, someone pointed out >> that symbol-macros basically allow you to define a symbol as an >> arbitrary "place", i.e. a kind of "place alias". >> >> Yet, it's subtly different since >> >> (symbol-macrolet ((x (nth 5 (get-list)))) ...) >> >> will re-execute (get-list) (and `nthcdr 5`) everytime `x` is used >> without offering any easy way to take advantage of the setf-expander >> infrastructure's ability to do those computations only once. >> >> Does anyone here know of work related to this, e.g. discussions about >> the detailed semantics of symbol-macrolet? > > We have probably discussed this before, but in TXR Lisp I provide > something called placelet. I found the prior discussion from 2016. In your response, you said that this is like gv-letplace. Thus, isn't gv-letplace what that user is looking for, instead of symbol-macrolet? symbol-macrolet cannot, and more importantly must not, be made to behave like gv-letplace or placelet. symbol-macrolet must adhere to its crystal-clear substitution model. symbol-macrolet doesn't have any non-obvious "detailed semantics". If a symbol is in an evaluated position, and lexically defined as a symbol macro in that scope, then we replace it with its definition (which is just a literal piece of structure with no parameters), and then walk that definition to expand more macros. The End.
[toc] | [prev] | [next] | [standalone]
| From | Stefan Monnier <monnier@iro.umontreal.ca> |
|---|---|
| Date | 2019-05-30 15:40 -0400 |
| Message-ID | <jwv1s0fd9ej.fsf-monnier+comp.lang.lisp@gnu.org> |
| In reply to | #32935 |
> In your response, you said that this is like gv-letplace.
> Thus, isn't gv-letplace what that user is looking for, instead of
> symbol-macrolet?
Rather it's just that the user pointed out the close relationship
between the two: you can implement a "place-alias" like your `letplace`
using `symbol-macrolet` and you can implement `symbol-macrolet` using
`letplace` (or so I presume, since we could do that with gv.el's
equivalent to your `letplace`).
So it made me wonder about this design space and whether maybe someone
has found something that's "more better" than either of the two.
Stefan
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <847-115-0292@kylheku.com> |
|---|---|
| Date | 2019-05-31 04:51 +0000 |
| Message-ID | <20190530214258.24@kylheku.com> |
| In reply to | #32996 |
On 2019-05-30, Stefan Monnier <monnier@iro.umontreal.ca> wrote: >> In your response, you said that this is like gv-letplace. >> Thus, isn't gv-letplace what that user is looking for, instead of >> symbol-macrolet? > > Rather it's just that the user pointed out the close relationship > between the two: you can implement a "place-alias" like your `letplace` > using `symbol-macrolet` and you can implement `symbol-macrolet` using > `letplace` (or so I presume, since we could do that with gv.el's > equivalent to your `letplace`). > > So it made me wonder about this design space and whether maybe someone > has found something that's "more better" than either of the two. By the way, I have discovered a quick and dirty "worse is better" way to implement place aliases. It's not 100% correct for all possible places, but it avoids requiring a "fully expand form" function. It also avoids registering temporary place expanders over the scope of a form. Thus, the approach is implementable in Common Lisp. This is located here: http://www.kylheku.com/cgit/lisp-snippets/tree/placelet.lisp The define-setf-expander call in placelet1 is useless and can be removed. The comments try to explain it. The idea is when we want to bind a symbol S to a place (P), what we do instead is obtain the setf expansion for (P) and bind S to the access form for (P). The issue is that by doing that, we ignore the store form. We are relying on the store form being deducible from the access form; i.e. that the access form is itself a place! For instance, an expression like (nthcdr 3 foo) might have an access form that looks like (cdr #:g0027). The store form will be some (rplaca #:g0027 #:g0031) type thing, but we ignore it. Lucky for as, the (cdr #:g0027) form is a place, and so we can make symbol macro S alias for this place. The approach will fail if the place has an access form that is itself not a place. But often, in fact usually I would say, place access forms are places. So this little hack is fairly practical. -- TXR Programming Lanuage: http://nongnu.org/txr Music DIY Mailing List: http://www.kylheku.com/diy ADA MP-1 Mailing List: http://www.kylheku.com/mp1
[toc] | [prev] | [next] | [standalone]
| From | "Pascal J. Bourguignon" <pjb@informatimago.com> |
|---|---|
| Date | 2019-05-31 16:38 +0200 |
| Message-ID | <m2r28e1yg8.fsf@despina.home> |
| In reply to | #32998 |
Kaz Kylheku <847-115-0292@kylheku.com> writes: > > The define-setf-expander call in placelet1 is useless and can be > removed. … > > Lucky for as, … > > The approach will fail … Why would you consider an approach that will fail??? You really wish catastrophes on your users and childrens? -- __Pascal J. Bourguignon__ http://www.informatimago.com
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <847-115-0292@kylheku.com> |
|---|---|
| Date | 2019-05-31 18:42 +0000 |
| Message-ID | <20190531112949.658@kylheku.com> |
| In reply to | #32999 |
On 2019-05-31, Pascal J. Bourguignon <pjb@informatimago.com> wrote: > Kaz Kylheku <847-115-0292@kylheku.com> writes: >> >> The define-setf-expander call in placelet1 is useless and can be >> removed. … >> >> Lucky for as, … >> >> The approach will fail … > > Why would you consider an approach that will fail??? It might fail to expand due to a form having no setf expansion being used as a place. The placelet1 macro could be easily refined to detect the situation, and provide an accurate diagnostic. Why I would consider the approach is that it's very simple and doesn't rely on any non-portable features. At least it's worth noting/documenting: "if we are able to take a certain requirement off the table, such and such highly simplified trick is possible which handles the remaining requirements". -- TXR Programming Lanuage: http://nongnu.org/txr Music DIY Mailing List: http://www.kylheku.com/diy ADA MP-1 Mailing List: http://www.kylheku.com/mp1
[toc] | [prev] | [next] | [standalone]
| From | "Pascal J. Bourguignon" <pjb@informatimago.com> |
|---|---|
| Date | 2019-05-31 21:24 +0200 |
| Message-ID | <m2muj21l7h.fsf@despina.home> |
| In reply to | #33001 |
Kaz Kylheku <847-115-0292@kylheku.com> writes: > On 2019-05-31, Pascal J. Bourguignon <pjb@informatimago.com> wrote: >> Kaz Kylheku <847-115-0292@kylheku.com> writes: >>> >>> The define-setf-expander call in placelet1 is useless and can be >>> removed. … >>> >>> Lucky for as, … >>> >>> The approach will fail … >> >> Why would you consider an approach that will fail??? > > It might fail to expand due to a form having no setf expansion being > used as a place. The placelet1 macro could be easily refined to detect > the situation, and provide an accurate diagnostic. > > Why I would consider the approach is that it's very simple and > doesn't rely on any non-portable features. > > At least it's worth noting/documenting: "if we are able to take a > certain requirement off the table, such and such highly simplified trick > is possible which handles the remaining requirements". Furthermore, even if one call to get-setf-expansion gives you a result such as (cdr #:foo), it doesn't mean that another call (notably with a different &environment, but possibly for any reason (eg. different optimization level, different run-time (OS where the same executable runs), etc could have given a different expression for the getter, one one hand, and on the other hand, there's also no guaranteed that the expression given by the getter be actually a place. Eg. you could get a (kdr #:foo) instead, with no (setf kdr). So basically, you need to perform the test, visually, which is worse than automatically, but you can also do it automatically, but it all comes down to perusing the section 5.1.2.2. http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_5-1-2-2.html Ie. you must make the decision when you write the code. -- __Pascal J. Bourguignon__ http://www.informatimago.com
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <847-115-0292@kylheku.com> |
|---|---|
| Date | 2019-06-01 02:34 +0000 |
| Message-ID | <20190531190747.275@kylheku.com> |
| In reply to | #33002 |
On 2019-05-31, Pascal J. Bourguignon <pjb@informatimago.com> wrote: > Kaz Kylheku <847-115-0292@kylheku.com> writes: > >> On 2019-05-31, Pascal J. Bourguignon <pjb@informatimago.com> wrote: >>> Kaz Kylheku <847-115-0292@kylheku.com> writes: >>>> >>>> The define-setf-expander call in placelet1 is useless and can be >>>> removed. … >>>> >>>> Lucky for as, … >>>> >>>> The approach will fail … >>> >>> Why would you consider an approach that will fail??? >> >> It might fail to expand due to a form having no setf expansion being >> used as a place. The placelet1 macro could be easily refined to detect >> the situation, and provide an accurate diagnostic. >> >> Why I would consider the approach is that it's very simple and >> doesn't rely on any non-portable features. >> >> At least it's worth noting/documenting: "if we are able to take a >> certain requirement off the table, such and such highly simplified trick >> is possible which handles the remaining requirements". > > Furthermore, even if one call to get-setf-expansion gives you a result > such as (cdr #:foo), it doesn't mean that another call (notably with a > different &environment, but possibly for any reason (eg. different Since CL doesn't have lexical setf-expansions, I think the enviornment is only used (and necessary) for expanding macros. So that is to say, if we want to obtain the setf expansion for some (foo) form, that form could be a macrolet in the given context. get-setf-expansion has to have the environment to resolve that. > optimization level, different run-time (OS where the same executable > runs), etc could have given a different expression for the getter, one > one hand, and on the other hand, there's also no guaranteed that the > expression given by the getter be actually a place. Eg. you could get a > (kdr #:foo) instead, with no (setf kdr). Yes. I constructed "artificial" places exactly like this when testing exploratory code in this area. This kind of place reliably produces an error when the code is doing it wrong. > So basically, you need to perform the test, visually, which is worse > than automatically, but you can also do it automatically, but it all > comes down to perusing the section 5.1.2.2. > http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_5-1-2-2.html > Ie. you must make the decision when you write the code. That doesn't really help. The solution is conceptually very simple: we create a temporary place like (#:G0025) which defers to the original place, using its access and store forms (my code shows this). We bind the desired alias symbol S to this (#:G0025) form and fully expand the code. All S's get converted to (#:G0025) and further, the expansion expand all (#:G0025) occurrences that are used as places. The these expansions will use the correct access and store form. Occurrences of (#:G0025) that are not used as places will stay unexpanded as (#:G0025); that symbol has no binding in the function/operator space. We then set up macrolet which binds (#:G0025) to the access form, and inject that expanded code into that macrolet; that code is our result. Thus the remaining occurrences which are pure accesses use the correct form also. We can't do this in one phase, because if we simultaneously have a S symbol macro expanding to (#:G0025) and a macrolet expanding (#:G0025) to the access form, these expansions both happen first; every single S, whether used as a place or not, is first reduced through (#:G0025) down to the the access form and we are back to square one: uses of S as a place are using the access form to deduce the store. This is the very situation exemplified in the code: the (macrolet ... (symbol-macrolet ...)) are combined into one piece of code with a single expansion phase, and that is the reason why the define-setf-expander form makes no difference, as the comment says. When the symbol-macrolet and macrolet expand, nothing is left in the code that interacts with the "proxy-place"; the code just contains references to the access form of the original place. Also, if we do fully expand the body code, then the proxy place (#:G0025) is no longer needed. We would like to delete it to reduce polution; alas, however, CL doesn't give us a portable way to undo the effect of define-setf-expander. In some systems it's keyed to a property of the symbol and whatnot. -- TXR Programming Lanuage: http://nongnu.org/txr Music DIY Mailing List: http://www.kylheku.com/diy ADA MP-1 Mailing List: http://www.kylheku.com/mp1
[toc] | [prev] | [next] | [standalone]
| From | Stefan Monnier <monnier@iro.umontreal.ca> |
|---|---|
| Date | 2019-05-31 18:14 -0400 |
| Message-ID | <jwvy32mjn3p.fsf-monnier+comp.lang.lisp@gnu.org> |
| In reply to | #33001 |
> Why I would consider the approach is that it's very simple and
> doesn't rely on any non-portable features.
I see the simplicity advantage, but not the portability advantage.
The way we'd implement it in Elisp, `placelet` would take the PLACE,
and extract from it a GETTER and a SETTER, and then do
(symbol-macrolet ((X (synthetic-place GETTER SETTER))) ...)
where `synthetic-place` is a globally defined generalized variable (as
well as a macro that just returns its first arg).
In Elisp's `gv.el` this is very straightforward and portable and doesn't
require an assumption about the ability to re-construct the GETTER from
the SETTER.
I haven't tried to implement it in Common-Lisp, but I can't see any
obvious reason why the same approach wouldn't work just as well.
Stefan
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <847-115-0292@kylheku.com> |
|---|---|
| Date | 2019-06-01 02:51 +0000 |
| Message-ID | <20190531193523.418@kylheku.com> |
| In reply to | #33004 |
On 2019-05-31, Stefan Monnier <monnier@iro.umontreal.ca> wrote: >> Why I would consider the approach is that it's very simple and >> doesn't rely on any non-portable features. > > I see the simplicity advantage, but not the portability advantage. > The way we'd implement it in Elisp, `placelet` would take the PLACE, > and extract from it a GETTER and a SETTER, and then do > > (symbol-macrolet ((X (synthetic-place GETTER SETTER))) ...) > > where `synthetic-place` is a globally defined generalized variable (as > well as a macro that just returns its first arg). This is the thing that fails in CL, which makes my code incorrect, as commented. Because if it's defined both as a macro that returns its first arg (alias for the getter) and as a generalized place then that macro always gets expanded, even if X is used as a place. I.e. given (incf X) X gets replaced by (synthetic-place G S), nicely enough. But that is immediately recognized as a macro and taken to G. So we end up with (incf G) ;; the access form; S ignored > In Elisp's `gv.el` this is very straightforward and portable and doesn't > require an assumption about the ability to re-construct the GETTER from > the SETTER. Aha! Maybe in Elisp, the GV framework doesn't macro-expand a place if that place is registered as a GV, even if it exists as a macro also. I.e. it gives priority to the place? I think I may have experimented with that order in TXR Lisp, but for whatever reason, I ended up with the CL approach: always blindly expand all macros, and only consider the form as a place once it is fully expanded. That could be the wrong approach: I will be certain to revisit that design decision. I do seem to recall I had a good reason. The opposite approach that I rejected does break macros in some ways. Say there is some global (foo) place. Now in my code, suppose I have a local macro (macrolet ((foo (...) ...))). My code is not aware of the global foo. This local foo *is* used as a place in my code: (incf (foo)). If this fails to expand my macro, but instead works with the global (foo) generalized place (giving it priority), that is surprising, and arguably breaks lexical scope: the macro should shadow everything. -- TXR Programming Lanuage: http://nongnu.org/txr Music DIY Mailing List: http://www.kylheku.com/diy ADA MP-1 Mailing List: http://www.kylheku.com/mp1
[toc] | [prev] | [next] | [standalone]
| From | Stefan Monnier <monnier@iro.umontreal.ca> |
|---|---|
| Date | 2019-06-02 12:16 -0400 |
| Message-ID | <jwvmuj0j7z6.fsf-monnier+comp.lang.lisp@gnu.org> |
| In reply to | #33006 |
> I.e. given
>
> (incf X)
>
> X gets replaced by (synthetic-place G S), nicely enough. But that is
> immediately recognized as a macro and taken to G. So we end up with
>
> (incf G) ;; the access form; S ignored
That sounds positively wrong: expansion of `incf` should happen before
we can know that (synthetic-place G S) is a Lisp expression (as opposed
to some data used by the macro some other way) that can be
macro-expanded, right?
> Aha! Maybe in Elisp, the GV framework doesn't macro-expand a place if
> that place is registered as a GV, even if it exists as a macro also.
> I.e. it gives priority to the place?
Exactly: the equivalent of get-setf-expansion first looks for a place
definition and only if that fails it falls back to looking for
a macro definition.
That seems to be the only good choice. I'm surprised, Common-Lisp is
not more careful with such ordering. It seems "out of character"
(seeing how it was careful to specify ordering of macroexpansion of
top-level `progn` forms, for example).
> I think I may have experimented with that order in TXR Lisp, but
> for whatever reason, I ended up with the CL approach: always blindly
> expand all macros, and only consider the form as a place once it
> is fully expanded.
But that choice simply disallows macros that are also setf-expander.
> That could be the wrong approach: I will be certain to revisit that
> design decision. I do seem to recall I had a good reason.
It can be tricky to get it right, admittedly (e.g. you need to use
macroexpand-1 so as to be able to check for the presence of
a setf-expander after each step of macroexpansion). We recently fixed
a bug in symbol-macrolet in this regard where it macroexpanded its args
before substituting them into the body.
> The opposite approach that I rejected does break macros in some ways.
> Say there is some global (foo) place. Now in my code, suppose I have a
> local macro (macrolet ((foo (...) ...))). My code is not aware of the
> global foo. This local foo *is* used as a place in my code: (incf
> (foo)). If this fails to expand my macro, but instead works with the
> global (foo) generalized place (giving it priority), that is surprising,
> and arguably breaks lexical scope: the macro should shadow everything.
I think this is a much more general problem: the place you define is
associated to the *symbol* foo and not to its macro definition.
The same holds for places defined on functions: if you define a global
function `bar`, then a place `bar` for it, and then use `flet` to
locally override this `bar` a `setf` will still use the global place you
defined, AFAIK. Same if you globally redefine the global macro/function
without redefining the place.
For this reason, in Elisp I prefer writing:
(defun FOO (ARGS)
(declare (gv-expander ...))
BODY)
over
(defun FOO (ARGS) BODY)
(gv-define-expander FOO ...)
even though currently, the implementation of the former just turns it
into the latter: at least the source code makes it clear that the
expander belongs to this particular function definition, and hopefully
in some future we will correctly associate the expander to the function
and not to its symbol.
Stefan
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <847-115-0292@kylheku.com> |
|---|---|
| Date | 2019-06-03 01:13 +0000 |
| Message-ID | <20190602174604.220@kylheku.com> |
| In reply to | #33007 |
On 2019-06-02, Stefan Monnier <monnier@iro.umontreal.ca> wrote: >> I.e. given >> >> (incf X) >> >> X gets replaced by (synthetic-place G S), nicely enough. But that is >> immediately recognized as a macro and taken to G. So we end up with >> >> (incf G) ;; the access form; S ignored > > That sounds positively wrong: expansion of `incf` should happen before > we can know that (synthetic-place G S) is a Lisp expression (as opposed > to some data used by the macro some other way) that can be > macro-expanded, right? Well, (incf <whatever>) knows that <whatever> is a place. It asks for the expansion with get-setf-expansion. But note that get-setf-expansion takes an &environment parameter: it expands the place first: first X goes to (synthetic-place...) and then to G. THen get-setf-expansion will get the expansion of G and return that. incf then works with that expansion. >> The opposite approach that I rejected does break macros in some ways. >> Say there is some global (foo) place. Now in my code, suppose I have a >> local macro (macrolet ((foo (...) ...))). My code is not aware of the >> global foo. This local foo *is* used as a place in my code: (incf >> (foo)). If this fails to expand my macro, but instead works with the >> global (foo) generalized place (giving it priority), that is surprising, >> and arguably breaks lexical scope: the macro should shadow everything. > > I think this is a much more general problem: the place you define is > associated to the *symbol* foo and not to its macro definition. > The same holds for places defined on functions: if you define a global > function `bar`, then a place `bar` for it, and then use `flet` to > locally override this `bar` a `setf` will still use the global place you > defined, AFAIK. Ah, but what if the access form of this global (bar ...j) place is simply the (bar ...) function call? (The overwhelmingly common case). That call will go to the local function. (incf (bar ...)) will call the local funtion to get the value, but use the store form from the the global setf expansion, like (bar-set ... new-value) or whatever. The situation is half-baked between global and local. However, with a macrolet, the user expects to hijack the (bar ...) form completely, in all its uses. If we macrolet (bar ...) to (car ...), we want (setf (bar ...) x) to do (setf (car ..) x) and forget the global (bar ...) place. This is why the CL approach is justifiable.
[toc] | [prev] | [next] | [standalone]
| From | Stefan Monnier <monnier@iro.umontreal.ca> |
|---|---|
| Date | 2019-05-31 18:04 -0400 |
| Message-ID | <jwv8suml1w0.fsf-monnier+comp.lang.lisp@gnu.org> |
| In reply to | #32996 |
> Rather it's just that the user pointed out the close relationship
> between the two: you can implement a "place-alias" like your `letplace`
> using `symbol-macrolet` and you can implement `symbol-macrolet` using
> `letplace` (or so I presume, since we could do that with gv.el's
> equivalent to your `letplace`).
In a sense, `symbol-macrolet` is a kind of "call-by-name" let-binding
(except it doesn't obey lexical scoping), whereas `placelet` is a kind
of "call by reference" let-binding.
> So it made me wonder about this design space and whether maybe someone
> has found something that's "more better" than either of the two.
The CBN/CBV/CBR analogy makes me suspect such a beast doesn't exist.
Stefan
[toc] | [prev] | [next] | [standalone]
| From | "Pascal J. Bourguignon" <pjb@informatimago.com> |
|---|---|
| Date | 2019-05-22 22:00 +0200 |
| Message-ID | <m2ftp6mf8f.fsf@despina.home> |
| In reply to | #32931 |
Stefan Monnier <monnier@iro.umontreal.ca> writes: > While discussing some extension to Elisp's `gv`, someone pointed out > that symbol-macros basically allow you to define a symbol as an > arbitrary "place", i.e. a kind of "place alias". > > Yet, it's subtly different since > > (symbol-macrolet ((x (nth 5 (get-list)))) ...) > > will re-execute (get-list) (and `nthcdr 5`) everytime `x` is used > without offering any easy way to take advantage of the setf-expander > infrastructure's ability to do those computations only once. > > Does anyone here know of work related to this, e.g. discussions about > the detailed semantics of symbol-macrolet? You're wrong. You can see that the macroexpansion uses get-setf-expander, which takes care of evaluating (get-list) only once: cl-user> (defmacro m (&environment env) `',(macroexpand-1 '(incf x) env)) m cl-user> (symbol-macrolet ((x (nth 5 (get-list)))) (m)) (let* ((#:g67596 (get-list)) (#:g67597 1) (#:g67595 (+ (nth 5 #:g67596) #:g67597))) (ccl::%setnth 5 #:g67596 #:g67595)) cl-user> -- __Pascal J. Bourguignon__ http://www.informatimago.com
[toc] | [prev] | [next] | [standalone]
| From | a.daniel.eliason@gmail.com |
|---|---|
| Date | 2019-05-23 08:10 -0700 |
| Message-ID | <e2f0ccdb-f1e8-4d1f-9572-af64c1f6120f@googlegroups.com> |
| In reply to | #32934 |
On Wednesday, May 22, 2019 at 10:00:37 PM UTC+2, informatimago wrote: > You're wrong. > ... > __Pascal J. Bourguignon__ > http://www.informatimago.com While I think we value direct communication on comp.lang.lisp, sometime's it's more polite to say something like, "Actually, that turns out not to be the case." -Daniel
[toc] | [prev] | [next] | [standalone]
| From | Spiros Bousbouras <spibou@gmail.com> |
|---|---|
| Date | 2019-05-23 15:22 +0000 |
| Message-ID | <JUyFE.426542$v12.107225@fx29.am4> |
| In reply to | #32939 |
On Thu, 23 May 2019 08:10:07 -0700 (PDT) a.daniel.eliason@gmail.com wrote: > On Wednesday, May 22, 2019 at 10:00:37 PM UTC+2, informatimago wrote: > > You're wrong. > > ... > > __Pascal J. Bourguignon__ > > http://www.informatimago.com > > While I think we value direct communication on comp.lang.lisp, sometime's > it's more polite to say something like, "Actually, that turns out not to > be the case." I find both statements equally polite.
[toc] | [prev] | [next] | [standalone]
| From | Dimitri Fontaine <dim@tapoueh.org> |
|---|---|
| Date | 2019-05-23 18:02 +0200 |
| Message-ID | <m2pno9gnw0.fsf@laptop.tapoueh.org> |
| In reply to | #32940 |
Spiros Bousbouras <spibou@gmail.com> writes: > On Thu, 23 May 2019 08:10:07 -0700 (PDT) > a.daniel.eliason@gmail.com wrote: >> On Wednesday, May 22, 2019 at 10:00:37 PM UTC+2, informatimago wrote: >> > You're wrong. >> >> While I think we value direct communication on comp.lang.lisp, sometime's >> it's more polite to say something like, "Actually, that turns out not to >> be the case." > > I find both statements equally polite. I sincerely don't think so. Look at the subject of the sentence. In the first case, the OP is the target. In the second case, what he said is the target. There's a world of difference there. I would assume that Pascal had a hard time writing what he meant on that one, and agree with the statement that his intervention was not polite, or let's face it, rude. Regards, -- dim
[toc] | [prev] | [next] | [standalone]
| From | Spiros Bousbouras <spibou@gmail.com> |
|---|---|
| Date | 2019-05-23 16:51 +0000 |
| Message-ID | <DcAFE.504630$Qy4.424505@fx04.am4> |
| In reply to | #32943 |
On Thu, 23 May 2019 18:02:23 +0200
Dimitri Fontaine <dim@tapoueh.org> wrote:
> Spiros Bousbouras <spibou@gmail.com> writes:
> > On Thu, 23 May 2019 08:10:07 -0700 (PDT)
> > a.daniel.eliason@gmail.com wrote:
> >> On Wednesday, May 22, 2019 at 10:00:37 PM UTC+2, informatimago wrote:
> >> > You're wrong.
> >>
> >> While I think we value direct communication on comp.lang.lisp, sometime's
> >> it's more polite to say something like, "Actually, that turns out not to
> >> be the case."
> >
> > I find both statements equally polite.
>
> I sincerely don't think so. Look at the subject of the sentence. In the
> first case, the OP is the target. In the second case, what he said is
> the target. There's a world of difference there.
"You are wrong" means "This statement you made is wrong" where the statement
is clear from the context. So the target in both cases is the statement. Who
or what is the subject of each sentence is a grammatical {syntactical ?}
technicality which doesn't affect the meaning and it's the meaning that
determines who or what is the referent i.e. "target".
> I would assume that Pascal had a hard time writing what he meant on that
> one,
I find such an assumption completely without basis.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <847-115-0292@kylheku.com> |
|---|---|
| Date | 2019-05-23 17:05 +0000 |
| Message-ID | <20190523100334.725@kylheku.com> |
| In reply to | #32940 |
On 2019-05-23, Spiros Bousbouras <spibou@gmail.com> wrote:
> On Thu, 23 May 2019 08:10:07 -0700 (PDT)
> a.daniel.eliason@gmail.com wrote:
>> On Wednesday, May 22, 2019 at 10:00:37 PM UTC+2, informatimago wrote:
>> > You're wrong.
>> > ...
>> > __Pascal J. Bourguignon__
>> > http://www.informatimago.com
>>
>> While I think we value direct communication on comp.lang.lisp, sometime's
>> it's more polite to say something like, "Actually, that turns out not to
>> be the case."
>
> I find both statements equally polite.
More importantly, they are both off the mark.
Stefan was talking about multiple references to the symbol-macro, like
(symbol-macrolet ((x (complicated-place)))
(list x x x)) ;; place evaluated three times
Yes, a single (incf x) expression will treat the place correctly
through the symbol macro, simply because it expands into
(incf (complicated-place)). But if we have (progn (incf x) (incf x)),
those two copies of the place know nothing about each other;
they don't share their evaluation.
--
TXR Programming Lanuage: http://nongnu.org/txr
Music DIY Mailing List: http://www.kylheku.com/diy
ADA MP-1 Mailing List: http://www.kylheku.com/mp1
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.lisp
csiph-web