Valentin Villenave <valen...@villenave.net> writes: > On 1/18/19, David Kastrup <d...@gnu.org> 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 _______________________________________________ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user