LilyPond und Scheme#

Die wichtigste Art, Scheme-Code in LilyPond einzufügen, ist die Verwendung des Hash-Zeichens ‚#‘. Es kennzeichnet einen einzelnen, vollständigen Scheme-Ausdruck, der ausgewertet wird. Sein Wert wird dann in den LilyPond-Kontext eingesetzt. Der spezielle Wert *unspecified*, den Ausdrücke ohne sinnvollen Wert zurückliefern (beispielsweise define-Klauseln), wird von LilyPond ignoriert.

Namensräume#

LilyPond-Namensräume sind auch Guile-Namensräume. Variablen, die in LilyPond definiert sind, sind in Scheme verfügbar und umgekehrt. Darüber hinaus definieren manche Blöcke eigene Namensräume, unter anderem \layout und \paper.

\version "2.25.8"

\layout {
  #(define myVar 5)
  indent = \myVar
}

{ c' }

% #myVar % würde einen Fehler auslösen!
Output../../images/bb5dd1d1f8a260673d08b1fdd3ed1c3ca5deeadf7b0a5892890639345a8b4c2b.svg

Hash- vs. Dollarzeichen#

Das Dollarzeichen $ ist eine zweite Art, Scheme-Ausdrücke einzufügen. Es funktioniert ein wenig anders:

  • Das Dollarzeichen erstellt eine Kopie des Werts des Ausdrucks.

  • Das Dollarzeichen wird zu einem früheren Zeitpunkt während des Parsens ausgewertet.

Der zweite Punkt ist etwas subtil. LilyPond benutzt einen Lexer und einen Parser, um die Eingabesyntax zu verstehen. Der Lexer arbeitet mit Tokens (den Wörtern vergleichbar), während der Parser die synaktische Struktur (wie die Grammatik eines Satzes) versteht. Der Parser erfordert dabei vom Lexer ein gewisses Maß an Vorausschau. Betrachten Sie beispielsweise den Satzanfang: „Lehrer Schmidt schrie laut …“. Eine mögliche Fortsetzung ist „… und drohte mit strengen Strafen“, eine andere „… seinem Kollegen Müller niemals im Klassenzimmer“. Im ersten Fall ist „laut“ ein (adverbial gebrauchtes) Adjektiv, im zweiten Fall eine Präposition mit Dativ. Um zu ermitteln, wie das Wort „laut“ zu interpretieren ist, ist es also nötig, vorauszulesen.

Scheme-Ausdrücke, die mit $ eingeleitet werden, werden sofort interpretiert, sobald sie vom Lexer eingelesen werden. Das ist nützlich, um Grundelemente der Eingabe mit Scheme zu konstruieren, beispielsweise:

\version "2.25.8"

stimmton = a'
{ $stimmton 4 }
Output../../images/06bf629b808a12b593c3f50b9ea854f1974570c39e04fcad6ae746dd3601e23a.svg

Dieser Code funktioniert! Die Variable stimmton wird vom Lexer sofort durch die Tonhöhe c‘ ersetzt, und der Parser bekommt von diesem Austausch nichts mit: Er sieht eine Tonhöhe, der eine Dauer folgt, und versteht diese Kombination als eine Note. Aus Sicht des Parsers ist { $stimmton 4 } (fast) äquivalent zu { a' 4 }

Ersetzt man aber das Dollar- durch ein Hashzeichen, funktioniert das Beispiel nicht mehr.

\version "2.25.8"

stimmton = a'
{ #stimmton 4 } % Warnung: Nicht-musikalischer Ausdruck wird ignoriert
Output../../images/e5c426e05e17be636bf853b58c1d297a34e4062e84ba5ec0efe94af8476afee3.svg

Denn was Parser jetzt sieht, ist ein zu evaluierender Scheme-Ausdruck, keine Tonhöhe. In dem Moment, in dem er entscheiden müsste, ob er diesen Ausdruck als Tonhöhe behandeln soll, kann er noch nicht wissen, dass dieser Ausdruck tatsächlich eine Tonhöhe liefert, und er möchte ihn auch zu diesem Zeitpunkt noch nicht auswerten.

Andererseits kann das Benutzen des Dollarzeichens durch das Vorauslesen auch unerwartete Effekte haben:

\version "2.25.8"

stimmton = a'
#(display stimmton)
Output../../images/8defaae1f3bd4fefb472aef4497562cad7ceec8f557b3dc5644f3152415b6878.svg

Das funktioniert nicht mehr, wenn das Hash- durch ein Dollarzeichen ersetzt wird:

stimmton = a'
$(display stimmton) % Fehler: Unbound variable: stimmton

Das liegt daran, dass der Parser vom Lexer beim Verarbeiten der Variablen-Definition ein weiteres Token anfordert, um sicher festzustellen, wie die Zuweisung zu interpretieren ist: Denn wäre das nächste Token die Dauer „8“, dann würde „a‘ 8“ gemeinsam als eine Achtelnote interpretiert werden, so dass die Variable stimmton eine Note enthielte und keine nackte Tonhöhe. Der Lexer aber versucht den eingelesenen Scheme-Ausdruck sofort auszuwerten (da er mit $ beginnt), und das muss scheitern: Denn die Zuweisung der Variable stimmton hat ja noch nicht stattgefunden.

Das Dollarzeichen erlaubt also, Scheme-Ausdrücke flexibel syntaktisch zu interpretieren, je nachdem, welche Art von Werten sie liefern. Das hat den Nachteil, dass die Ausdrücke frühzeitig ausgewertet werden müssen.

Im allgemeinen sollte man meistens das Hash-Zeichen # verwenden, außer in Ausnahmefällen, bei denen das Dollarzeichen $ Syntax-Tricks ermöglicht oder man mit ihm bequem einen Wert kopieren kann.