Guide, node Updating translation committishes..
@end ignore
-@c \version "2.15.20"
+@c \version "2.19.21"
@node Scheme tutorial
@chapter Scheme tutorial
There are also compound data types in Scheme. The types commonly used in
LilyPond programming include pairs, lists, alists, and hash tables.
-@subheading Pairs
+@menu
+* Pairs::
+* Lists::
+* Association lists (alists)::
+* Hash tables::
+@end menu
+
+@node Pairs
+@unnumberedsubsubsec Pairs
The foundational compound data type of Scheme is the @code{pair}. As
might be expected from its name, a pair is two values glued together.
@lisp
guile> (define mypair (cons 123 "hello there")
-... )
+@dots{} )
guile> (car mypair)
123
guile> (cdr mypair)
Abelson, see
@uref{http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133}
-@subheading Lists
+@node Lists
+@unnumberedsubsubsec Lists
-A very common Scheme data structure is the @emph{list}. Formally, a
-list is defined as either the empty list (represented as @code{'()},
-or a pair whose @code{cdr} is a list.
+A very common Scheme data structure is the @emph{list}. Formally,
+a @q{proper} list is defined to be either the empty list with its
+input form @code{'()} and length@tie{}0, or a pair whose
+@code{cdr} in turn is a shorter list.
There are many ways of creating lists. Perhaps the most common is
with the @code{list} procedure:
a dialect of lisp, where @q{lisp} is an abbreviation for
@q{List Processing}. Scheme expressions are all lists.
-@subheading Association lists (alists)
+@node Association lists (alists)
+@unnumberedsubsubsec Association lists (alists)
A special type of list is an @emph{association list} or @emph{alist}.
An alist is used to store data for easy retrieval.
Alists are widely used in LilyPond to store properties and other data.
-@subheading Hash tables
+@node Hash tables
+@unnumberedsubsubsec Hash tables
A data structure that is used occasionally in LilyPond. A hash table
is similar to an array, but the indexes to the array can be any type
value resulting from their execution. They can also manipulate
variables defined outside of the procedure.
-@subheading Defining procedures
+@menu
+* Defining procedures::
+* Predicates::
+* Return values::
+@end menu
+
+@node Defining procedures
+@unnumberedsubsubsec Defining procedures
Procedures are defined in Scheme with define
15/2
@end lisp
-@subheading Predicates
+@node Predicates
+@unnumberedsubsubsec Predicates
Scheme procedures that return boolean values are often called
@emph{predicates}. By convention (but not necessity), predicate names
#f
@end lisp
-@subheading Return values
+@node Return values
+@unnumberedsubsubsec Return values
Scheme procedures always return a return value, which is the value
of the last expression executed in the procedure. The return
@lisp
guile> (let ((x 2) (y 3) (z 4)) (display (+ x y)) (display (- z 4))
-... (+ (* x y) (/ z x)))
+@dots{} (+ (* x y) (/ z x)))
508
@end lisp
@node Scheme conditionals
@subsection Scheme conditionals
-@subheading if
+@menu
+* if::
+* cond::
+@end menu
+
+@node if
+@unnumberedsubsubsec if
Scheme has an @code{if} procedure:
"a is not greater than b"
@end lisp
-@subheading cond
+@node cond
+@unnumberedsubsubsec cond
Another conditional procedure in scheme is @code{cond}:
@example
(cond (test-expression-1 result-expression-sequence-1)
(test-expression-2 result-expression-sequence-2)
- ...
+ @dots{}
(test-expression-n result-expression-sequence-n))
@end example
* LilyPond Scheme syntax::
* LilyPond variables::
* Input variables and Scheme::
+* Importing Scheme in LilyPond::
* Object properties::
* LilyPond compound variables::
* Internal music representation::
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,
-@ruser{LilyPond grammar}. Once it knows that a particular syntax rule
+@rcontrib{LilyPond grammar}. Once it knows that a particular syntax rule
applies, it executes actions associated with it.
The hash mark@tie{}@code{#} method of embedding Scheme is a natural fit
This is, in fact, exactly the same mechanism that Lilypond employs when
you call any variable or music function by name, as @code{\name}, with
-the only difference that its end is determined by the Lilypond lexer
+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 @code{$} can lead to surprises, @ref{Input
-variables and Scheme}. Using @code{#} where the parser supports it is
-usually preferable.
+variables and Scheme}. Using @code{#} where the parser supports it
+is usually preferable. Inside of music expressions, expressions
+created using @code{#} @emph{are} interpreted as music. However,
+they are @emph{not} copied before use. If they are part of some
+structure that might still get used, you may need to use
+@code{ly:music-deep-copy} explicitly.
+
+@funindex $@@
+@funindex #@@
+There are also @q{list splicing} operators @code{$@@} and @code{#@@}
+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:
is internally converted to a Scheme definition:
@example
-(define traLaLa @var{Scheme value of `@code{... }'})
+(define traLaLa @var{Scheme value of `@code{@dots{}}'})
@end example
This means that LilyPond variables and Scheme variables may be freely
#(define twice
(make-sequential-music newLa))
-{ \twice }
+\twice
@end lilypond
@c Due to parser lookahead
evaluating it, so it can go ahead with the assignment, and
@emph{afterwards} execute the Scheme code without problem.
+@node Importing Scheme in LilyPond
+@subsection Importing Scheme in LilyPond
+@funindex $
+@funindex #
+
The above example shows how to @q{export} music expressions from the
input to the Scheme interpreter. The opposite is also possible. By
placing it after @code{$}, a Scheme
been written as
@example
-...
-@{ $(make-sequential-music (list newLa)) @}
+@dots{}
+$(make-sequential-music newLa)
@end example
You can use @code{$} with a Scheme expression anywhere you could use
would not yet have been defined. For an explanation of this timing
problem, @ref{LilyPond Scheme syntax}.
-In any case, evaluation of Scheme code happens in the parser at latest.
-If you need it to be executed at a later point of time, @ref{Void scheme
-functions}, or store it in a macro:
+@funindex $@@
+@funindex #@@
+A further convenience can be the @q{list splicing} operators @code{$@@}
+and @code{#@@} for inserting the elements of a list in the surrounding
+context. Using those, the last part of the example could have been
+written as
+
+@example
+@dots{}
+@{ #@@newLa @}
+@end example
+
+Here, every element of the list stored in @code{newLa} is taken in
+sequence and inserted into the list, as if we had written
+
+@example
+@{ #(first newLa) #(second newLa) @}
+@end example
+
+Now in all of these forms, the Scheme code is evaluated while the
+input is still being consumed, either in the lexer or in the parser.
+If you need it to be executed at a later point of time, check out
+@ref{Void scheme functions}, or store it in a procedure:
@example
#(define (nopc)
(ly:set-option 'point-and-click #f))
-...
+@dots{}
#(nopc)
@{ c'4 @}
@end example
this is:
@example
-\override Stem #'thickness = #2.6
+\override Stem.thickness = #2.6
@end example
This instruction adjusts the appearance of stems. An alist entry
@node LilyPond compound variables
@subsection LilyPond compound variables
-@subheading Offsets
+@menu
+* Offsets::
+* Fractions::
+* Extents::
+* Property alists::
+* Alist chains::
+@end menu
+
+@node Offsets
+@unnumberedsubsubsec Offsets
Two-dimensional offsets (X and Y coordinates) are stored as @emph{pairs}.
The @code{car} of the offset is the X coordinate, and the @code{cdr} is
the Y coordinate.
@example
-\override TextScript #'extra-offset = #'(1 . 2)
+\override TextScript.extra-offset = #'(1 . 2)
@end example
This assigns the pair @code{(1 . 2)} to the @code{extra-offset}
Procedures for working with offsets are found in @file{scm/lily-library.scm}.
-@subheading Fractions
+@node Fractions
+@unnumberedsubsubsec Fractions
Fractions as used by LilyPond are again stored as @emph{pairs}, this
time of unsigned integers. While Scheme can represent rational numbers
means @code{(2 . 4)} in Scheme, and @code{#2/4} in LilyPond means
@code{1/2} in Scheme.
-@subheading Extents
+@node Extents
+@unnumberedsubsubsec Extents
Pairs are also used to store intervals, which represent a range of numbers
from the minimum (the @code{car}) to the maximum (the @code{cdr}).
@file{scm/lily-library.scm}. These procedures should be used when possible
to ensure consistency of code.
-@subheading Property alists
+@node Property alists
+@unnumberedsubsubsec Property alists
A property alist is a LilyPond data structure that is an alist whose
keys are properties and whose values are Scheme expressions that give
LilyPond properties are Scheme symbols, such as @code{'thickness}.
-@subheading Alist chains
+@node Alist chains
+@unnumberedsubsubsec Alist chains
An alist chain is a list containing property alists.
'text
"f"))
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 0 0))))
@end example
By default, LilyPond will print these messages to the console along
with all the other messages. To split up these messages and save
-the results of @code{\display@{STUFF@}}, redirect the output to
-a file.
+the results of @code{\display@{STUFF@}}, you can specify an optional
+output port to use:
@example
-lilypond file.ly >display.txt
+@{
+ \displayMusic #(open-output-file "display.txt") @{ c'4\f @}
+@}
@end example
-With a combined bit of Lilypond and Scheme magic, you can actually
-let Lilypond direct just this output to a file of its own:
-
+This will overwrite a previous output file whenever it is called; if you
+need to write more than one expression, you would use a variable for
+your port and reuse it:
@example
@{
- $(with-output-to-file "display.txt"
- (lambda () #@{ \displayMusic @{ c'4\f @} #@}))
+ port = #(open-output-file "display.txt")
+ \displayMusic \port @{ c'4\f @}
+ \displayMusic \port @{ d'4 @}
+ #(close-output-port port)
@}
@end example
+Guile's manual describes ports in detail. Closing the port is actually
+only necessary if you need to read the file before Lilypond finishes; in
+the first example, we did not bother to do so.
A bit of reformatting makes the above information easier to read:
(make-music 'AbsoluteDynamicEvent
'text
"f"))
- 'duration (ly:make-duration 2 0 1 1)
+ 'duration (ly:make-duration 2 0 1/1)
'pitch (ly:make-pitch 0 0 0))))
@end example
-A @code{@{ ... @}} music sequence has the name @code{SequentialMusic},
-and its inner expressions are stored as a list in its @code{'elements}
-property. A note is represented as a @code{NoteEvent} object (storing
-the duration and pitch properties) with attached information (in this
-case, an @code{AbsoluteDynamicEvent} with a @code{"f"} text property)
-stored in its @code{articulations} property.
+A @code{@{ @dots{} @}} music sequence has the name
+@code{SequentialMusic}, and its inner expressions are stored as a list
+in its @code{'elements} property. A note is represented as a
+@code{NoteEvent} object (storing the duration and pitch properties) with
+attached information (in this case, an @code{AbsoluteDynamicEvent} with
+a @code{"f"} text property) stored in its @code{articulations} property.
@funindex{\void}
@code{\displayMusic} returns the music it displays, so it will get
(make-music
'NoteEvent
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 0 0))
@end example
(list (make-music
'NoteEvent
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 0 0))))
@end example
(make-music
'NoteEvent
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 0 0))
@end example
(ly:make-pitch 0 1 0)) ;; set the pitch to d'.
\displayLilyMusic \someNote
===>
-d'
+d'4
@end example
'span-direction
-1))
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 5 0))
(make-music
'span-direction
1))
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 5 0))))
@end example
(make-music
'NoteEvent
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch 0 5 0))))
@end example
So in our function, we need to clone this expression (so that we have
two notes to build the sequence), add a @code{SlurEvent} to the
@code{'articulations} property of each one, and finally make a
-@code{SequentialMusic} with the two @code{EventChords}. For adding to a
+@code{SequentialMusic} with the two @code{NoteEvent} elements. For adding to a
property, it is useful to know that an unset property is read out as
@code{'()}, the empty list, so no special checks are required before we
put another element at the front of the @code{articulations} property.
@subsection Adding articulation to notes (example)
The easy way to add articulation to notes is to merge two music
-expressions into one context, as explained in @ruser{Creating contexts}.
+expressions into one context.
However, suppose that we want to write a music function that does this.
This will have the additional advantage that we can use that music
function to add an articulation (like a fingering instruction) to a
single note inside of a chord which is not possible if we just merge
independent music.
-A @code{$variable} inside the @code{#@{...#@}} notation is like
+A @code{$variable} inside the @code{#@{@dots{}#@}} notation is like
a regular @code{\variable} in classical LilyPond notation. We
know that
(make-music
'NoteEvent
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch -1 0 0))))
=====
'articulation-type
"accent"))
'duration
- (ly:make-duration 2 0 1 1)
+ (ly:make-duration 2 0 1/1)
'pitch
(ly:make-pitch -1 0 0))
@end example
too!)
@example
-"Add an accent..."
+"Add an accent@dots{}"
@end example
@noindent
We have seen how LilyPond output can be heavily modified using
commands like
-@code{\override TextScript #'extra-offset = ( 1 . -1)}. But
+@code{\override TextScript.extra-offset = ( 1 . -1)}. But
we have even more power if we use Scheme. For a full explanation
of this, see the @ref{Scheme tutorial}, and
@ref{Interfaces for programmers}.
@lilypond[quote,verbatim,ragged-right]
padText = #(define-music-function (parser location padding) (number?)
#{
- \once \override TextScript #'padding = #padding
+ \once \override TextScript.padding = #padding
#})
-\relative c''' {
- c4^"piu mosso" b a b
+\relative {
+ c'''4^"piu mosso" b a b
\padText #1.8
c4^"piu mosso" d e f
\padText #2.6
@lilypond[quote,verbatim,ragged-right]
tempoPadded = #(define-music-function (parser location padding tempotext)
- (number? string?)
+ (number? markup?)
#{
- \once \override Score.MetronomeMark #'padding = $padding
+ \once \override Score.MetronomeMark.padding = #padding
\tempo \markup { \bold #tempotext }
#})
\relative c'' {
\tempo \markup { "Low tempo" }
c4 d e f g1
- \tempoPadded #4.0 #"High tempo"
+ \tempoPadded #4.0 "High tempo"
g4 f e d c1
}
@end lilypond
@lilypond[quote,verbatim,ragged-right]
pattern = #(define-music-function (parser location x y) (ly:music? ly:music?)
#{
- $x e8 a b $y b a e
+ #x e8 a b #y b a e
#})
\relative c''{