Andy Wingo <wi...@pobox.com> writes: > On Tue 13 Dec 2011 17:54, David Kastrup <d...@gnu.org> writes: > >>> Am I missing something? >> >> Performance, space, simplicity, robustness. Compiling five closures >> that do nothing except accessing a single variable each is a bit >> wasteful. > > Sure. > > Let me see if I finally understand the issue here: > > You have a function: > > (define-music-function (foo bar) > (ly:something? bar) ^^^^^^^^^^^^^^^^^^^ Those are predicates, not arguments. > #{ /la /la /la > $bar $bar $bar > #(scheme-expression!)
Both # and $ come before Scheme expressions. # is the regular type visible in the parser, and has, for example, the property that it will always serve as exactly one argument of a music function. $ is an "immediate" type that gets camouflaged as a Lilypond token right in the lexer. Using $ for assignments or less static cases than above is prone to surprises since the parser generally operates with one token of lookahead, and $ has to be evaluated before a token even exists. In contrast, # is read in the lexer and evaluated in the parser. So basically the Guile relevant angle of the two is identical. > /ok }#) > Before, you could turn the #{}# into a lambda No, it was turned into a reader expansion. No closure. The reader expansion had as constant contents the #{ ... #} contents as a string, and a capture of the current lexical environment. When this got executed, the parser is let loose on the #{ ... #} contents, and when encountering $ or #, it evaluates them like it would do outside of #{ ... #} except for using a local-eval in the captured environment. In either case, the Scheme reader is used for skipping over the sexp following $ and #. That is still done, but instead of throwing the read sexp away, we now put it in a lambda together with its position in the string (unless it is an obvious constant). When evaluating # or $ at runtime, we first check the alist of positions to lambdas, and if we find a record of that position, evaluate a call to the recorded lambda instead of the read expression. Of course, this is not good for producing lvalues (pardon the Cism). > and get at the $vars and evaluate the #(expressions) in the > procedure-environment of the lambda. Now, you have to munge around in > the expression and, in this case, produce 4 closures: (lambda () bar), > 3 times, and (lambda () (scheme-expression!)). > > Is that right? Yes, that's what we currently do. I don't know whether Scheme will be smart enough to use the same memoization for all lambdas in (list (cons 1 (lambda () bar)) (cons 5 (lambda () bar)) (cons 13 (lambda () bar))) And it is a nuisance that one can't cons that thing together in the reader and just quote it at runtime, because the read extension works in the wrong lexical environment to produce the right kind of lambda. One could at best use two lists instead of an alist, and at least code the position list as a single constant. -- David Kastrup