lilypond-user
[Top][All Lists]
Advanced

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

Re: select a note in a chord


From: David Kastrup
Subject: Re: select a note in a chord
Date: Fri, 18 Jan 2019 01:06:54 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

Valentin Villenave <address@hidden> writes:

> On 1/18/19, David Kastrup <address@hidden> wrote:
>> This is not really an issue for string-manipulation.
>
> Agreed. Nevertheless, I was pleasantly surprised to see that
> ly:parser-include-string could accept an incomplete expression.
> (Previously, ly:parser-parse-string would have been much less flexible
> here.)
>
>> Let's rather do this in a sane manner:
>
> Indeed, a named "let" loop is clearly the preferred way to go!
>
> That being said, I still wonder if there’d be any way of making it
> work with either iota or make-list without having to go through string
> manipulations. (It would remove the need for a loop with an
> incremented counter.)

You can use something like
(fold (if (negative? num) drop rise)
      music
      (make-list (abs num) 1))

but I don't like creating lists for the sake of controlling loop size.

> And btw, why does mapping onto (iota num) require a lambda (x)
> function even though that x argument does absolutely nothing? My
> instinct would be to use lambda (), but that throws an error.

You cannot call functions with a different number of arguments than they
are defined.  A map is a _map_.  Of course it takes an argument.  If you
want to express "this function ignores whatever arguments it may
receives" you can write (lambda _ ... ) and the whole argument list
would be assigned to _ (by convention a subsequently ignored binding).

>>            ((negative? num) (loop (1+ num) #{ \drop 1 #music #}))
>>            (else (loop (1- num) #{ \rise 1 #music #})))))
>
> Why #music and not $music inside the #{ #}? (I suspect there’s no
> difference in this case, but $music is the more familiar syntax
> inherited from before your parser/lexer improvements.)

#music is an as-is Scheme expression, $music is evaluated and copied
before assigning a syntactical category.  If you aren't using the
expression elsewhere, those copies are unnecessary.

I mean, it's documented.  The "Extending LilyPond Guide" has this to
say:


1.2.1 LilyPond Scheme syntax
----------------------------

The Guile interpreter is part of LilyPond, which means that Scheme can
be included in LilyPond input files.  There are several methods for
including Scheme in LilyPond.

   The simplest way is to use a hash mark ‘#’ before a Scheme
expression.

   Now LilyPond’s input is structured into tokens and expressions, much
like human language is structured into words and sentences.  LilyPond
has a lexer that recognizes tokens (literal numbers, strings, Scheme
elements, pitches and so on), and a parser that understands the syntax,
*note (lilypond-contributor)LilyPond grammar::.  Once it knows that a
particular syntax rule applies, it executes actions associated with it.

   The hash mark ‘#’ method of embedding Scheme is a natural fit for
this system.  Once the lexer sees a hash mark, it calls the Scheme
reader to read one full Scheme expression (this can be an identifier, an
expression enclosed in parentheses, or several other things).  After the
Scheme expression is read, it is stored away as the value for an
‘SCM_TOKEN’ in the grammar.  Once the parser knows how to make use of
this token, it calls Guile for evaluating the Scheme expression.  Since
the parser usually requires a bit of lookahead from the lexer to make
its parsing decisions, this separation of reading and evaluation between
lexer and parser is exactly what is needed to keep the execution of
LilyPond and Scheme expressions in sync.  For this reason, you should
use the hash mark ‘#’ for calling Scheme whenever this is feasible.

   Another way to call the Scheme interpreter from LilyPond is the use
of dollar ‘$’ instead of a hash mark for introducing Scheme expressions.
In this case, LilyPond evaluates the code right after the lexer has read
it.  It checks the resulting type of the Scheme expression and then
picks a token type (one of several ‘xxx_IDENTIFIER’ in the syntax) for
it.  It creates a _copy_ of the value and uses that for the value of the
token.  If the value of the expression is void (Guile’s value of
‘*unspecified*’), nothing at all is passed to the parser.

   This is, in fact, exactly the same mechanism that LilyPond employs
when you call any variable or music function by name, as ‘\name’, with
the only difference that the name is determined by the LilyPond lexer
without consulting the Scheme reader, and thus only variable names
consistent with the current LilyPond mode are accepted.

   The immediate action of ‘$’ can lead to surprises, see *note
Importing Scheme in LilyPond::.  Using ‘#’ where the parser supports it
is usually preferable.  Inside of music expressions, expressions created
using ‘#’ _are_ interpreted as music.  However, they are _not_ copied
before use.  If they are part of some structure that might still get
used, you may need to use ‘ly:music-deep-copy’ explicitly.


-- 
David Kastrup



reply via email to

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