Prev: Lisp sucks!
Next: grabbing key presses
From: Spiros Bousbouras on 17 Nov 2009 17:02 On 17 Nov, 18:01, "Tobias C. Rittweiler" <t...(a)freebits.de.invalid> wrote: > Spiros Bousbouras <spi...(a)gmail.com> writes: > > > In my code above nothing is leaking but my code doesn't do what I > > want. In the solutions posted by the two Pascals a symbol-macro cell > > is introduced in the global environment. That's what's leaking. In > > Pascal B.'s solution also the dynamic variable *cell* is leaking. > > Pascal Costanza's example contained a global symbol macro, though you > don't need it. How can you do the same thing without a global symbol macro ? > Are internally used functions to implement other functions also an > example of leaking? Or variables? They all introduce stuff into the > global environment. What's the difference? What do you mean "internally" ? Show me some code and I'll tell you. > > The ability to expand macros is a good thing. As I said in my opening > > post , if Lisp had a minimal-compile function (which in a sense would > > be a stronger version of macroexpand) , I could do what I want in a > > clean and more elegant manner. Actually I find it surprising that it > > doesn't. minimal-compile would be more or less something which does > > more than macroexpand but less than eval. > > It's commonly called MACROEXPAND-ALL. Brilliant. I will return to this, probably in a different thread. > > And the issues here are elegance , practicality and even speed of > > compilation. > > How does MACROEXPAND-ALL help the speed of compilation? I'm not sure that it will but I thought that if it makes the implementation of certain macros simpler or the expanded code smaller then this might help the speed of compilation. > Using it, the > implementation has to walk the syntax tree twice. Yes but the second time it won't have to expand any macros. So on one hand it might make the macroexpansion function or the expanded code of some macros smaller but on the other it will have to parse some stuff twice. I was thinking that in some cases the first may outweigh the second. > Do you know that it can in fact lead to an _impairment_ of runtime speed > because implementation which would previously implement some macros as > special forms cannot do so? No I didn't know it. Can you give me an example of something an implementation can do without MACROEXPAND-ALL that it couldn't do if MACROEXPAND-ALL existed ? -- But, to wring a new twist on an old phrase, power corrupts. And Mississippi Burning is corrupted by the reckless exhilaration it betrays in wielding its own pumped-up, self-inflated cinematic power. http://cinepad.com/reviews/mississippi.htm
From: Spiros Bousbouras on 17 Nov 2009 17:06 On 17 Nov, 20:15, Pascal Costanza <p...(a)p-cos.net> wrote: > Spiros Bousbouras wrote: > > On 11 Nov, 00:40, Pascal Costanza <p...(a)p-cos.net> wrote: > >> Spiros Bousbouras wrote: > > >>> (let ((a 0)) > >>> (defmacro memory (&rest body) > >>> (prog2 > >>> (incf a) > >>> `(symbol-macrolet ((cell ,a)) > >>> ,@body) > >>> (decf a)))) [...] > > Is there any established way for how such parallel > > expansion/compilation is supposed to work ? Intuitively it seems to > > me that in the scenario you're describing the implementation ought to > > create one copy of a for the compilation and another for any > > expansions which are not part of the compilation. If it doesn't do > > that what makes you think that even your code will work correctly ? > > There may be clashes with the use of new-cell-value. > > Huh? new-cell-value is lexically bound, so it's guaranteed to have its > own binding per invocation. Guaranteed by what ? This situation is not covered by the standard , is it ? In any case in my code the variable a is also lexically bound. -- Who's your mama ?
From: Pascal Costanza on 18 Nov 2009 03:00 Spiros Bousbouras wrote: > On 17 Nov, 20:15, Pascal Costanza <p...(a)p-cos.net> wrote: >> Spiros Bousbouras wrote: >>> On 11 Nov, 00:40, Pascal Costanza <p...(a)p-cos.net> wrote: >>>> Spiros Bousbouras wrote: >>>>> (let ((a 0)) >>>>> (defmacro memory (&rest body) >>>>> (prog2 >>>>> (incf a) >>>>> `(symbol-macrolet ((cell ,a)) >>>>> ,@body) >>>>> (decf a)))) > > [...] > >>> Is there any established way for how such parallel >>> expansion/compilation is supposed to work ? Intuitively it seems to >>> me that in the scenario you're describing the implementation ought to >>> create one copy of a for the compilation and another for any >>> expansions which are not part of the compilation. If it doesn't do >>> that what makes you think that even your code will work correctly ? >>> There may be clashes with the use of new-cell-value. >> Huh? new-cell-value is lexically bound, so it's guaranteed to have its >> own binding per invocation. > > Guaranteed by what ? This situation is not covered by the standard , > is it ? Lexical bindings? Of course they are covered by the standard. > In any case in my code the variable a is also lexically bound. But you're performing side effects on this lexically bound variable, which may lead to race conditions when multiple threads expand this one macro. This is then a situation of concurrent write accesses to shared memory, which usually need to be synchronized. In a 'pure binding' (purely functional) situation, you don't have these problems. Yes, _multithreading_ is not covered by the standard, but there are numerous multithreaded Common Lisp implementations, so if you want your code to be portable, you better take that into account. 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/
From: Tobias C. Rittweiler on 18 Nov 2009 17:51 Spiros Bousbouras <spibou(a)gmail.com> writes: > On 17 Nov, 18:01, "Tobias C. Rittweiler" wrote: > > > Spiros Bousbouras <spi...(a)gmail.com> writes: > > > > > In my code above nothing is leaking but my code doesn't do what I > > > want. In the solutions posted by the two Pascals a symbol-macro cell > > > is introduced in the global environment. That's what's leaking. In > > > Pascal B.'s solution also the dynamic variable *cell* is leaking. > > > > Pascal Costanza's example contained a global symbol macro, though you > > don't need it. > > How can you do the same thing without a global symbol macro ? (defmacro memory (&body body &environment env) (multiple-value-bind (old-cell-value expandedp) (macroexpand 'cell env) `(symbol-macrolet ((cell ,(1+ (if expandedp old-cell-value 0)))) ,@body))) > > Are internally used functions to implement other functions also an > > example of leaking? Or variables? They all introduce stuff into the > > global environment. What's the difference? > > What do you mean "internally" ? Show me some code and I'll tell you. (defpackage :foof (:use :cl) (:export #:frobf)) (in-package :foof) (defun internal-fn (x) (* x x) (defun frobf (x y) (+ (internal-fn x) y)) A function (INTERNAL-FN) is introduced in the global environment solely to implement the behaviour of FROBF. In your definition quoted above, it's leaking something. > > Do you know that it can in fact lead to an _impairment_ of runtime speed > > because implementation which would previously implement some macros as > > special forms cannot do so? > > No I didn't know it. Can you give me an example of something an > implementation can do without MACROEXPAND-ALL that it couldn't do if > MACROEXPAND-ALL existed ? Say your implementation implements DOLIST as a special form[*] for reasons of efficiency. In case of (defun foo (list &aux (sum 0)) (dolist (i list sum) (incf sum i))) the implementation can process DOLIST as a special form. Contrarily on: (defmacro walk-at-compile-time (form &environment env) (macroexpand-all form env)) (defun bar (list &aux (sum 0)) (walk-at-compile-time (dolist (i list sum) (incf sum i)))) the implementation has to expand the DOLIST form into something probably involving TAGBODY. We assumed that the implementation as special form would be more efficient -- so this shows how code-walking can impose runtime penalty. -T. [*] This is not just an academic point. For example, ABCL's interpreter implements DOLIST etc. as special form because it can then execute the loop directly in Java instead of having to interpret a Lisp loop.
From: Spiros Bousbouras on 20 Nov 2009 07:40
On 17 Nov, 14:48, Pillsy <pillsb...(a)gmail.com> wrote: > On Nov 10, 4:36 pm, Spiros Bousbouras <spi...(a)gmail.com> wrote: > [...] > > > In any case, it seems that if one wants to have macros share > > information (apart from trivial cases perhaps) then this cannot be > > achieved behind the scenes so to speak. What I mean behind the scenes > > is the way you would do it with functions: > > (let ((a)) > > (defun foo ... > > (defun bar ...) > > Any changes to a one function makes the other knows about but the > > rest of the code is ignorant about a. > > This is a trick I've used once or twice in the past, and I'm just > submitting it as an idea in part because I'd like to see if there are > problems with it that I haven't considered up until now. It's hardly > something I do every day, and I know this corner of macrology is > generally riddled with pitfalls. > > The idea is that you have easy access to uninterned symbols, and those > symbols not only have their value cells, but also function cells and > property lists to play with. You could do something like this: > > (let ((closed (closed "BACKING-"))) Is the second "closed" meant to be "gensym" ? > (defmacro foo (name &rest args) > (setf (get closed name) (stuff-from-foo-args args)) > (generate-foo-expansion name args closed)) > (defmacro bar (name &rest args) > (setf (get closed name) (stuff-from-bar-args args)) > (generate-bar-expansion name args closed))) > > Is there something horribly wrong with this approach? I'm afraid I don't understand what the various ingredients like closed , name , stuff-from-foo-args are supposed to do. Could you post some specific example which uses your technique ? Nevertheless your code gave me the idea for the following approach: (let ((a (gensym "memory-var-"))) (defmacro memory (&body body) `(progn (if (boundp ',a) (incf ,a) (defvar ,a 1)) (symbol-macrolet ((cell ,a)) (prog1 ,@body (decf ,a)))))) It solves the problem of "reserving" for itself a name for a global symbol. And yes , I know it uses side effects but I'm not convinced this is something worrying about. -- Who's your mama ? |