lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: simple scheme function #{ $note #}


From: Aaron Hill
Subject: Re: simple scheme function #{ $note #}
Date: Sat, 12 May 2018 09:04:40 -0700
User-agent: Roundcube Webmail/1.3.6

On 2018-05-11 23:01, David Kastrup wrote:
The reason why #{ $p #} does not work as the body of a music function
is that it will only evaluate to a pitch not a note, and that pitch by
itself is not enough to create a music expression.

Wrong again.  There is no such thing as a "pitch by itself" in Scheme.
A pitch is not a deficient music expression, rather it is not a music
expression at all. It's like saying a character by itself is not enough
to create a string, as if two characters by itself would create a
string.  Strings are not the same as characters of any count.

Strings are a separate data structure from characters.  You can place
characters in other data structures.  You can certainly also form
one-character strings.

(make-music 'NoteEvent 'pitch #{ c' #})

is a music expression a music function can return (it's deficient for a
number of unchanged uses in that it is lacking a duration but you can
add durations afterwards if you want to with different music functions).

Two pitches are not enough to create a music expression.  Ten pitches
aren't.  If you want to create a music expression, you need to create a
music expression, like using make-music.  Or use some #{ ... #}
construct recognized as producing music.

#{ $p 4 #} works because a pitch followed by a duration clearly
defines a note, which is enough to form a music expression.

#{ $p #} #{ 4 #} is a pitch followed by a duration and does not form a
music expression.  The music expression is created by specific forms of
the #{ ... #} syntax.

Okay, then none of this makes any logical sense.

It is my understanding that #{ #} is an escaping mechanism. Its purpose is to facilitate mixing LilyPond syntax within a Scheme construct. At the end of the day, everything that is input to the LilyPond program becomes one long Scheme expression. LilyPond syntax is essentially nothing more than a convenient abbreviation for equivalent Scheme.

To that end, there is a parser involved in processing LilyPond syntax to generate the desired Scheme expressions. It sounded like the underlying issue with the original poster's error was that of a limitation during parsing. To simply include "c'" by itself within #{ #} causes the parser to only generate enough Scheme for the specified NOTENAME_PITCH token which would be an ly:pitch. This looked to me to be similar to when you only include "c'" by itself in a LilyPond file and try to compile it. You minimally need to enclose it in braces to give the parser some context. As such, that is why I offered a solution of #{ { $p } #}, since that successfully gets around the error.

Of course, I tried something just now that I should have tried before. That is, what happens with a file containing only "c' d'"? Oh, well, it fails to compile as well. Crud. So my conclusion that the parser in general is able to figure out what is meant by a sequence of bare pitches is wrong. The parser really does need more context to make sense of things. However, that does not immediately explain why #{ c' d' #} works. It would seem that it should fail for similar reasons.

There is clearly magic in #{ #} that is non-obvious here. But why is its behavior inconsistent? Surely if #{ c' d' #} is "smart" enough to interpret two bare pitches as a sequence of notes with assumed durations, why can it not do the same for a single pitch. Or, said another way, HOW does one actually make #{ $p #} work for a music function? Certainly, #{ { $p } #} and #{ <> $p #} both appear to work for producing music with the pitch as a note, and you provided a way to verbosely use make-music for the task. Is there no other way to force #{ #} to interpret its contents as producing music?

At this point, I must confess that I tell a lie. To say this makes no logical sense was hyperbolic. Is this not, as I have tried and failed to relay, simply an issue of mismatched types? #{ $p #} results in a pitch not music. That is why it cannot be the sole body of a music function. Music functions must return music, and #{ #} will never evaluate to music if provided a bare pitch as input. You are left with an ly:pitch that needs extra work to become music.

If so, that actually does make sense. It would be madness if #{ #} always tried to form a music expression with whatever you gave it, since that would give you no way of easily expressing the myriad of other syntactic element types within Scheme. Your explicit make-music example for instance must rely on #{ c' #} evaluating only to a pitch for the purposes of defining the NoteEvent.

Now, #{ c' d' #} could be interpreted in one of two ways. Is this a list of two pitches, or is this a music expression formed by two notes without explicit durations? The latter seems to be the more common use case, so understandably that is what happens. And right there is the magic. The parser normally would not accept two bare pitches as music; but within the #{ #} construct it does consider that as sufficient to produce music.

This would run counter to your assertion that "[two] pitches are not enough to create a music expression." Outside of the #{ #} construct, yes, that appears to be the case. A LilyPond file with just "a b c" will not work, and I was wrong if I implied that in my post. However, this discussion is about the #{ #} construct. And within the #{ #} construct, the parser, it would seem, follows different rules allowing #{ a b c #} to produce music but not #{ a #}.

Something like #{ a #} #{ 2 #} is an entirely different scenario altogether. <insert "Airplane" reference here> As you have introduced a second #{ #} construct, it should be no surprise the parser will treat each construct individually. As neither ly:pitch nor ly:duration is valid to return from a music function, define-music-function is unhappy.

And this would disagree with your comment that "There is no such thing as a 'pitch by itself' in Scheme.". There very much is such a thing as a pitch in Scheme. The type ly:pitch alone is evidence of that, otherwise the premise of the original poster's music function is flawed. Perhaps what you intended to stress is that a music expression within Scheme cannot consist of a pitch (or duration) by itself. Let's pretend for a moment that #{ a #} and #{ 2 #} could evaluate to music. They would each end up defining a NoteEvent. The ly:pitch and ly:duration values would be properties of their respective events and therefore would not be standing alone within the expression.

But this all reinforces the crux of the confusion: that #{ #} sometimes evaluates to music and sometimes does not. While this behavior can be helpful, surely it must be the entire reason why the original poster's function does not work as intended.

-- Aaron Hill



reply via email to

[Prev in Thread] Current Thread [Next in Thread]