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, 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 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.

There are also ‘list splicing’ operators $@ and #@ that insert all elements of a list in the surrounding context.

Now let’s take a look at some actual Scheme code. Scheme procedures can be defined in LilyPond input files:

#(define (average a b c) (/ (+ a b c) 3))

Note that LilyPond comments (% and %{ %}) cannot be used within Scheme code, even in a LilyPond input file, because the Guile interpreter, not the LilyPond lexer, is reading the Scheme expression. Comments in Guile Scheme are entered as follows:

; this is a single-line comment

#!
  This a (non-nestable) Guile-style block comment
  But these are rarely used by Schemers and never in
  LilyPond source code
!#

For the rest of this section, we will assume that the data is entered in a music file, so we add a # at the beginning of each Scheme expression.

All of the top-level Scheme expressions in a LilyPond input file can be combined into a single Scheme expression by use of the begin statement:

#(begin
  (define foo 0)
  (define bar 1))

LilyPond — Extending v2.23.82 (development-branch).