[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: music macros?
From: |
Erik Sandberg |
Subject: |
Re: music macros? |
Date: |
Sat, 4 Feb 2006 00:07:04 +0100 |
User-agent: |
KMail/1.8.3 |
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
- Re: music function refactoring, Erik Sandberg, 2006/02/01
- Re: music function refactoring, Han-Wen Nienhuys, 2006/02/01
- Re: music function refactoring, Erik Sandberg, 2006/02/01
- music macros?, Han-Wen Nienhuys, 2006/02/01
- Re: music macros?, Erik Sandberg, 2006/02/02
- Re: music macros?, Nicolas Sceaux, 2006/02/03
- Re: music macros?,
Erik Sandberg <=
- Re: music macros?, Nicolas Sceaux, 2006/02/04
- Re: music macros?, Han-Wen Nienhuys, 2006/02/04
- Re: music macros?, Nicolas Sceaux, 2006/02/04
- Re: music macros?, Erik Sandberg, 2006/02/04
- Re: music macros?, Han-Wen Nienhuys, 2006/02/05
- Re: music macros?, Erik Sandberg, 2006/02/06
- Re: music function refactoring, Han-Wen Nienhuys, 2006/02/01