]> git.donarmstrong.com Git - lilypond.git/blobdiff - Documentation/extending/scheme-tutorial.itely
Doc: Extending - rewrite - LilyPond Variables
[lilypond.git] / Documentation / extending / scheme-tutorial.itely
index b73c2bb9fd7ad7b91e0c193d98257dfc71af6bac..5984c4f038c926d962627ef67aafb5b6cf1e886f 100644 (file)
@@ -8,7 +8,7 @@
     Guide, node Updating translation committishes..
 @end ignore
 
-@c \version "2.17.6"
+@c \version "2.19.22"
 
 @node Scheme tutorial
 @chapter Scheme tutorial
@@ -72,7 +72,7 @@ see @rlearning{Other sources of information}.  Alternatively, Windows
 users may simply choose @q{Run} from the Start menu and enter
 @q{guile}.
 
-However, a hands-on Scheme sandbox with all of Lilypond loaded is
+However, a hands-on Scheme sandbox with all of LilyPond loaded is
 available with this command line:
 @example
 lilypond scheme-sandbox
@@ -258,7 +258,7 @@ Scheme procedures @code{car} and @code{cdr}, respectively.
 
 @lisp
 guile> (define mypair (cons 123 "hello there")
-... )
+@dots{} )
 guile> (car mypair)
 123
 guile> (cdr mypair)
@@ -275,9 +275,10 @@ Abelson, see
 @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:
@@ -287,12 +288,19 @@ guile> (list 1 2 3 "abc" 17.5)
 (1 2 3 "abc" 17.5)
 @end lisp
 
-As can be seen, a list is displayed in the form of individual elements
-separated by whitespace and enclosed in parentheses.  Unlike a pair,
-there is no period between the elements.
+Representing a list as individual
+elements separated by whitespace and enclosed in parentheses
+is actually a compacted rendition of the actual dotted pairs
+constituting the list, where the dot and an immediately following
+starting paren are removed along with the matching closing paren.
+Without this compaction, the output would have been
+@lisp
+(1 . (2 . (3 . ("abc" . (17.5 . ())))))
+@end lisp
 
-A list can also be entered as a literal list by enclosing its
-elements in parentheses, and adding a quote:
+As with the output, a list can also be entered (after adding a
+quote to avoid interpretation as a function call) as a literal
+list by enclosing its elements in parentheses:
 
 @lisp
 guile> '(17 23 "foo" "bar" "bazzle")
@@ -574,7 +582,7 @@ statement in the let block:
 
 @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
 
@@ -615,7 +623,7 @@ 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
 
@@ -679,7 +687,7 @@ feasible.
 
 Another way to call the Scheme interpreter from LilyPond is the use of
 dollar@tie{}@code{$} instead of a hash mark for introducing Scheme
-expressions.  In this case, Lilypond evaluates the code right after the
+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
 @code{xxx_IDENTIFIER} in the syntax) for it.  It creates a @emph{copy}
@@ -687,18 +695,18 @@ of the value and uses that for the value of the token.  If the value of
 the expression is void (Guile's value of @code{*unspecified*}), nothing
 at all is passed to the parser.
 
-This is, in fact, exactly the same mechanism that Lilypond employs when
+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 the name 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.  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
+consistent with the current LilyPond mode are accepted.
+
+The immediate action of @code{$} can lead to surprises, see
+@ref{Importing Scheme in LilyPond}.  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 $@@
@@ -730,11 +738,11 @@ as follows:
 @end example
 
 For the rest of this section, we will assume that the data is entered
-in a music file, so we add@tie{}@code{#}s at the beginning of each Scheme
+in a music file, so we add a @code{#} 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 the use of the
+be combined into a single Scheme expression by use of the
 @code{begin} statement:
 
 @example
@@ -769,17 +777,28 @@ twentyFour = #(* 2 twelve)
 @end example
 
 @noindent
-which would result in the number 24 being stored in the
-LilyPond (and Scheme) variable @code{twentyFour}.
-
-The usual way to refer to Lilypond variables, @ref{LilyPond Scheme
-syntax}, is to call them using a backslash, i.e., @code{\twentyFour}.
-Since this creates a copy of the value for most of LilyPond's internal
-types, in particular music expressions, music functions don't usually
-create copies of material they change.  For this reason, music
-expressions given with @code{#} should usually not contain material that
-is not either created from scratch or explicitly copied rather than
-directly referenced.
+which would result in the number @emph{24} being stored in the LilyPond
+(and Scheme) variable @code{twentyFour}.
+
+Scheme allows modifying complex expressions in-place and LilyPond makes
+use of this @q{in-place modification} when using music functions.  But
+when music expressions are stored in variables rather than entered
+directly the usual expectation, when passing them to music functions,
+would be that the original value is unmodified.  So when referencing a
+music variable with leading backslash (such as @code{\twentyFour}),
+LilyPond creates a copy of that variable's music value for use in the
+surrounding music expression rather than using the variable's value
+directly.
+
+Therefore, Scheme music expressions written with the @code{#} syntax
+should be used for material that is created @q{from scratch} (or that is
+explicitly copied) rather than being used, instead, to directly
+reference material.
+
+@seealso
+Extending:
+@ref{LilyPond Scheme syntax}.
+
 
 @node Input variables and Scheme
 @subsection Input variables and Scheme
@@ -820,7 +839,7 @@ traLaLa = @{ c'4 d'4 @}
 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
@@ -862,14 +881,14 @@ Instead of defining @code{\twice}, the example above could also have
 been written as
 
 @example
-...
+@dots{}
 $(make-sequential-music newLa)
 @end example
 
 You can use @code{$} with a Scheme expression anywhere you could use
 @code{\@var{name}} after having assigned the Scheme expression to a
 variable @var{name}.  This replacement happens in the @q{lexer}, so
-Lilypond is not even aware of the difference.
+LilyPond is not even aware of the difference.
 
 One drawback, however, is that of timing.  If we had been using @code{$}
 instead of @code{#} for defining @code{newLa} in the above example, the
@@ -885,7 +904,7 @@ context.  Using those, the last part of the example could have been
 written as
 
 @example
-...
+@dots{}
 @{ #@@newLa @}
 @end example
 
@@ -905,7 +924,7 @@ If you need it to be executed at a later point of time, check out
 #(define (nopc)
   (ly:set-option 'point-and-click #f))
 
-...
+@dots{}
 #(nopc)
 @{ c'4 @}
 @end example
@@ -1104,7 +1123,7 @@ to create complicated music functions.
 
 When writing a music function it is often instructive to inspect how
 a music expression is stored internally.  This can be done with the
-music function @code{\displayMusic}
+music function @code{\displayMusic}.
 
 @example
 @{
@@ -1127,51 +1146,58 @@ will display
                   '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:
 
 @example
 (make-music 'SequentialMusic
   'elements (list
-            (make-music 'NoteEvent
+             (make-music 'NoteEvent
                'articulations (list
-                              (make-music 'AbsoluteDynamicEvent
-                                'text
-                                "f"))
-              'duration (ly:make-duration 2 0 1 1)
-              'pitch    (ly:make-pitch 0 0 0))))
+                               (make-music 'AbsoluteDynamicEvent
+                                           'text
+                                           "f"))
+               '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
@@ -1181,9 +1207,11 @@ interpreted as well as displayed.  To avoid interpretation, write
 @node Music properties
 @subsection Music properties
 
+@ignore
 TODO -- make sure we delineate between @emph{music} properties,
 @emph{context} properties, and @emph{layout} properties.  These
 are potentially confusing.
+@end ignore
 
 Let's look at an example:
 
@@ -1194,7 +1222,7 @@ someNote = c'
 (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
@@ -1212,7 +1240,7 @@ someNote = <c'>
   (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
@@ -1230,13 +1258,13 @@ expression.
 (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
 
 Then the note pitch is accessed through the @code{'pitch} property
-of the @code{NoteEvent} object,
+of the @code{NoteEvent} object.
 
 @example
 #(display-scheme-music
@@ -1246,7 +1274,7 @@ of the @code{NoteEvent} object,
 (ly:make-pitch 0 0 0)
 @end example
 
-The note pitch can be changed by setting this @code{'pitch} property,
+The note pitch can be changed by setting this @code{'pitch} property.
 
 @funindex \displayLilyMusic
 
@@ -1256,7 +1284,7 @@ The note pitch can be changed by setting this @code{'pitch} property,
        (ly:make-pitch 0 1 0)) ;; set the pitch to d'.
 \displayLilyMusic \someNote
 ===>
-d'
+d'4
 @end example
 
 
@@ -1281,7 +1309,7 @@ representation of the desired result.
                   '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
@@ -1292,7 +1320,7 @@ representation of the desired result.
                   '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
@@ -1301,7 +1329,7 @@ The bad news is that the @code{SlurEvent} expressions
 must be added @q{inside} the note (in its @code{articulations}
 property).
 
-Now we examine the input,
+Now we examine the input.
 
 @example
 \displayMusic a'
@@ -1309,7 +1337,7 @@ Now we examine the input,
 (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
@@ -1317,13 +1345,13 @@ Now we examine the input,
 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.
 
 @example
-doubleSlur = #(define-music-function (parser location note) (ly:music?)
+doubleSlur = #(define-music-function (note) (ly:music?)
          "Return: @{ note ( note ) @}.
          `note' is supposed to be a single note."
          (let ((note2 (ly:music-deep-copy note)))
@@ -1348,7 +1376,7 @@ 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
 
@@ -1366,7 +1394,7 @@ the articulation to an empty chord,
 
 @noindent
 but for the sake of this example, we will learn how to do this in
-Scheme.  We begin by examining our input and desired output,
+Scheme.  We begin by examining our input and desired output.
 
 @example
 %  input
@@ -1375,7 +1403,7 @@ Scheme.  We begin by examining our input and desired output,
 (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))))
 =====
@@ -1390,7 +1418,7 @@ Scheme.  We begin by examining our input and desired output,
           '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
@@ -1420,7 +1448,7 @@ from its name.  (this is good practice in other programming languages,
 too!)
 
 @example
-"Add an accent..."
+"Add an accent@dots{}"
 @end example
 
 @noindent
@@ -1494,12 +1522,12 @@ Finally, once we have added the accent articulation to its
 @code{articulations} property, we can return @code{note-event}, hence
 the last line of the function.
 
-Now we transform the @code{add-accent} function into a music
-function (a matter of some syntactic sugar and a declaration of the type
-of its sole @q{real} argument).
+Now we transform the @code{add-accent} function into a music function (a
+matter of some syntactic sugar and a declaration of the type of its
+argument).
 
 @example
-addAccent = #(define-music-function (parser location note-event)
+addAccent = #(define-music-function (note-event)
                                      (ly:music?)
   "Add an accent ArticulationEvent to the articulations of `note-event',
   which is supposed to be a NoteEvent expression."
@@ -1510,7 +1538,7 @@ addAccent = #(define-music-function (parser location note-event)
   note-event)
 @end example
 
-We may verify that this music function works correctly,
+We then verify that this music function works correctly:
 
 @example
 \displayMusic \addAccent c4
@@ -1544,13 +1572,13 @@ TODO Find a simple example
 
 @ignore
 @lilypond[quote,verbatim,ragged-right]
-padText = #(define-music-function (parser location padding) (number?)
+padText = #(define-music-function (padding) (number?)
 #{
   \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
@@ -1567,16 +1595,16 @@ We can use it to create new commands:
 
 
 @lilypond[quote,verbatim,ragged-right]
-tempoPadded = #(define-music-function (parser location padding tempotext)
+tempoPadded = #(define-music-function (padding tempotext)
   (number? markup?)
 #{
   \once \override Score.MetronomeMark.padding = #padding
   \tempo \markup { \bold #tempotext }
 #})
 
-\relative c'' {
+\relative {
   \tempo \markup { "Low tempo" }
-  c4 d e f g1
+  c''4 d e f g1
   \tempoPadded #4.0 "High tempo"
   g4 f e d c1
 }
@@ -1586,7 +1614,7 @@ tempoPadded = #(define-music-function (parser location padding tempotext)
 Even music expressions can be passed in:
 
 @lilypond[quote,verbatim,ragged-right]
-pattern = #(define-music-function (parser location x y) (ly:music? ly:music?)
+pattern = #(define-music-function (x y) (ly:music? ly:music?)
 #{
   #x e8 a b #y b a e
 #})