On Thursday 02 February 2006 02.35, Han-Wen Nienhuys wrote: > Erik Sandberg wrote: > > Yes, just represent those commands as music functions internally. E.g., > > \transpose creates a MusicFunction expression, with a list of two pitches > > and one Music as its 'elements (or 'arguments, I haven't decided yet), > > and 'to-music-callback is set to ly:music-transpose (or rather, to a > > wrapper around that function). > > OK, so we create all music expressions/events as "Music promises", which > expand into Music objects via some function as soon as they are > inspected, but have \relative deal with music-promises directly?
How about this: The parser spits out a big evaluatable Scheme expression, which simply is eval:ed after parsing. A bit like the return value of music->make-music, but with music functions & macros written as real Scheme functions. The good thing about this solution, is the simplicity and the powerfulness (I suppose that lots of things would be handled automatically by Scheme, perhaps we will even get local variables for free). The bad thing, is that the \relative macro will be rather ugly (it will need to traverse (make-music ..) calls and modify pitches). The approach requires quite large changes to the parser: All identifiers (both functions and variables) need to be treated equal, which means that: { c \partcombine f g } is parsed into (eval-list ((make-music ...) partcombine (make-music ...) (make-music ...))) which, when evaluated, becomes the same as: (list 'c (partcombine 'f 'g)) I.e., parentheses are added where appropriate, using our knowledge of partcombine's arity. The reason why this must be done after parsing, is that variables can be assigned functions during "runtime". /* The eval-list function would look something like: (define (eval-list ls) (if (pair? ls) (let ((a (car ls)) (d (cdr ls))) (if (procedure? a) (let ((arity (car (procedure-property a 'arity)))) (cons (primitive-eval (cons a (list-head d arity))) (eval-list (list-tail d arity)))) (cons a (eval-list d)))) ls)) .. plus a special case for macros. */ This is the basic idea. The structure can be cleaned up further: E.g., we write our own list evaluation function, so we can just as well store Music objects directly, instead of make-music calls, and make a special case in eval-list. This would make the \relative macro a bit cleaner. Given the mechanisms described above, I think it's pretty straightforward to write a .ly file which defines a full functional language, that uses lilypond-style syntax. (e.g. fun = \lambda {\x \y} {c8 d \x e4 \y \y }) -- Erik _______________________________________________ lilypond-devel mailing list lilypond-devel@gnu.org http://lists.gnu.org/mailman/listinfo/lilypond-devel