X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fextending%2Fscheme-tutorial.itely;h=4c180538f5e9ed8246bfbb821063fdb0341f825d;hb=1d509b27723ea1c359b51c0f2fe623a32867d6f9;hp=c0430762d140589bfc7b68a9084812bb3c8cfb64;hpb=8bee60d3ccd267d9ca4a27adeb56683e2f764008;p=lilypond.git diff --git a/Documentation/extending/scheme-tutorial.itely b/Documentation/extending/scheme-tutorial.itely index c0430762d1..4c180538f5 100644 --- a/Documentation/extending/scheme-tutorial.itely +++ b/Documentation/extending/scheme-tutorial.itely @@ -4,10 +4,11 @@ Translation of GIT committish: FILL-IN-HEAD-COMMITTISH When revising a translation, copy the HEAD committish of the - version that you are working on. See TRANSLATION for details. + version that you are working on. For details, see the Contributors' + Guide, node Updating translation committishes.. @end ignore -@c \version "2.12.0" +@c \version "2.14.0" @node Scheme tutorial @chapter Scheme tutorial @@ -27,9 +28,9 @@ Scheme. If you want to know more about Scheme, see @uref{http://@/www@/.schemers@/.org}. LilyPond uses the GNU Guile implementation of Scheme, which is -based on the Scheme @qq{R5RS} standard. If you are learning Scheme +based on the Scheme @qq{R5RS} standard. If you are learning Scheme to use with LilyPond, working with a different implementation (or -referring to a different standard) is not recommended. Information +referring to a different standard) is not recommended. Information on guile can be found at @uref{http://www.gnu.org/software/guile/}. The @qq{R5RS} Scheme standard is located at @uref{http://www.schemers.org/Documents/Standards/R5RS/}. @@ -67,12 +68,12 @@ Scheme. On most systems you can experiment in a Scheme sandbox by opening a terminal window and typing @q{guile}. On some systems, notably Windows, you may need to set the environment variable @code{GUILE_LOAD_PATH} to the directory @code{../usr/shr/guile/1.8} -in the LilyPond installation. For the full path to this directory +in the LilyPond installation. For the full path to this directory see @rlearning{Other sources of information}. Alternatively, Windows users may simply choose @q{Run} from the Start menu and enter @q{guile}. -Once the guile sandbox is running, you will received a guile prompt: +Once the guile sandbox is running, you will receive a guile prompt: @lisp guile> @@ -102,7 +103,7 @@ guile> a guile> @end lisp -Scheme variables can be printed on the display by use of the display function: +Scheme variables can be printed on the display by using the display function: @lisp guile> (display a) @@ -110,9 +111,9 @@ guile> (display a) @end lisp @noindent -Note that the value @code{2} and the guile prompt @code{guile} both -showed up on the same line. This can be avoided by calling the newline -procedure or displaying a newline character. +Note that both the value @code{2} and the guile prompt @code{guile} +showed up on the same line. This can be avoided by calling the +newline procedure or displaying a newline character. @lisp guile> (display a)(newline) @@ -147,11 +148,11 @@ and False is @code{#f}. @item Numbers Numbers are entered in the standard fashion, -@code{1} is the (integer) number one, while @code{-1.5} is a +@code{1} is the (integer) number one, while @w{@code{-1.5}} is a floating point number (a non-integer number). @item Strings -Strings are enclosed in double quotes, +Strings are enclosed in double quotes: @example "this is a string" @@ -197,7 +198,7 @@ For a complete listing see the Guile reference guide, There are also compound data types in Scheme. The types commonly used in LilyPond programming include pairs, lists, alists, and hash tables. -@unnumberedsubsubsec Pairs +@subheading 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. @@ -252,8 +253,7 @@ Note: @code{cdr} is pronounced "could-er", according Sussman and Abelson, see @uref{http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133} - -@unnumberedsubsubsec Lists +@subheading Lists A very common Scheme data structure is the @emph{list}. Formally, a list is defined as either the empty list (represented as @code{'()}, @@ -283,7 +283,7 @@ Lists are a central part of Scheme. In, fact, Scheme is considered a dialect of lisp, where @q{lisp} is an abbreviation for @q{List Processing}. Scheme expressions are all lists. -@unnumberedsubsubsec Association lists (alists) +@subheading 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. @@ -307,7 +307,7 @@ guile> Alists are widely used in LilyPond to store properties and other data. -@unnumberedsubsubsec Hash tables +@subheading 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 @@ -390,19 +390,30 @@ be used for another calculation. @lisp guile> (+ 1 (* 3 4)) 13 -guile> (+ 1 (* 3 4)) @end lisp These calculations are examples of evaluations; an expression like @code{(* 3 4)} is replaced by its value @code{12}. -When the scheme parser encounters an expression that is a list, the -first element of the list is treated as a procedure to be evaluated -with the arguments of the remainder of the list. Therefore, all operators -in Scheme are prefix operators. +Scheme calculations are sensitive to the differences between integers +and non-integers. Integer calculations are exact, while non-integers +are calculated to the appropriate limits of precision: + +@lisp +guile> (/ 7 3) +7/3 +guile> (/ 7.0 3.0) +2.33333333333333 +@end lisp + +When the scheme interpreter encounters an expression that is a list, +the first element of the list is treated as a procedure to be +evaluated with the arguments of the remainder of the list. Therefore, +all operators in Scheme are prefix operators. -If the first element of a Scheme expression that is a list passed to the parser -is @emph{not} an operator or procedure, an error will occur: +If the first element of a Scheme expression that is a list passed to +the interpreter is @emph{not} an operator or procedure, an error will +occur: @lisp guile> (1 2 3) @@ -417,10 +428,11 @@ ABORT: (misc-error) guile> @end lisp -Here you can see that the interpreter was trying to treat 1 as an operator -or procedure, and it couldn't. Hence the error is "Wrong type to apply: 1". +Here you can see that the interpreter was trying to treat 1 as an +operator or procedure, and it couldn't. Hence the error is "Wrong +type to apply: 1". -To create a list, then , we need to use the list operator, or we need to +Therefore, to create a list we need to use the list operator, or to quote the list so that the interpreter will not try to evaluate it. @lisp @@ -461,19 +473,124 @@ The quote mark @code{'} prevents the Scheme interpreter from substituting @node Scheme procedures @subsection Scheme procedures -@unnumberedsubsubsec Predicates +Scheme procedures are executable scheme expressions that return a +value resulting from their execution. They can also manipulate +variables defined outside of the procedure. + +@subheading Defining procedures + +Procedures are defined in Scheme with define + +@example +(define (function-name arg1 arg2 ... argn) + scheme-expression-that-gives-a-return-value) +@end example + +For example, we could define a procedure to calculate the average: + +@lisp +guile> (define (average x y) (/ (+ x y) 2)) +guile> average +# +@end lisp + +Once a procedure is defined, it is called by putting the procedure +name and the arguments in a list. For example, we can calculate +the average of 3 and 12: + +@lisp +guile> (average 3 12) +15/2 +@end lisp + +@subheading Predicates -@unnumberedsubsubsec Return values +Scheme procedures that return boolean values are often called +@emph{predicates}. By convention (but not necessity), predicate names +typically end in a question mark: -TODO -- write about scheme procedures +@lisp +guile> (define (less-than-ten? x) (< x 10)) +guile> (less-than-ten? 9) +#t +guile> (less-than-ten? 15) +#f +@end lisp + +@subheading Return values + +Scheme procedures always return a return value, which is the value +of the last expression executed in the procedure. The return +value can be any valid Scheme value, including a complex data +structure or a procedure. + +Sometimes the user would like to have multiple Scheme expressions in +a procedure. There are two ways that multiple expressions can be +combined. The first is the @code{begin} procedure, which allows +multiple expressions to be evaluated, and returns the value of +the last expression. + +@lisp +guile> (begin (+ 1 2) (- 5 8) (* 2 2)) +4 +@end lisp + +The second way to combine multiple expressions is in a @code{let} block. +In a let block, a series of bindings are created, and then a sequence +of expressions that can include those bindings is evaluated. The +return value of the let block is the return value of the last +statement in the let block: + +@lisp +guile> (let ((x 2) (y 3) (z 4)) (display (+ x y)) (display (- z 4)) +... (+ (* x y) (/ z x))) +508 +@end lisp @node Scheme conditionals @subsection Scheme conditionals -@unnumberedsubsubsec if +@subheading if + +Scheme has an @code{if} procedure: + +@example +(if test-expression true-expression false-expression) +@end example + +@var{test-expression} is an expression that returns a boolean +value. If @var{test-expression} returns @code{#t}, the if +procedure returns the value of @var{true-expression}, otherwise +it returns the value of @var{false-expression}. + +@lisp +guile> (define a 3) +guile> (define b 5) +guile> (if (> a b) "a is greater than b" "a is not greater than b") +"a is not greater than b" +@end lisp + +@subheading 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) + ... + (test-expression-n result-expression-sequence-n)) +@end example -@unnumberedsubsubsec cond +For example: +@lisp +guile> (define a 6) +guile> (define b 8) +guile> (cond ((< a b) "a is less than b") +... ((= a b) "a equals b") +... ((> a b) "a is greater than b")) +"a is less than b" +@end lisp @node Scheme in LilyPond @section Scheme in LilyPond @@ -491,20 +608,25 @@ TODO -- write about scheme procedures @node LilyPond Scheme syntax @subsection LilyPond Scheme syntax -In a music file, snippets of Scheme code are introduced with the hash -mark @code{#}. So, the previous examples translated to LilyPond are +The Guile interpreter is part of LilyPond, which means that +Scheme can be included in LilyPond input files. The hash mark@tie{}@code{#} +is used to tell the LilyPond parser that the next value is a Scheme +value. + +Once the parser sees a hash mark, input is passed to the Guile +interpreter to evaluate the Scheme expression. The interpreter continues +to process input until the end of a Scheme expression is seen. + +Scheme procedures can be defined in LilyPond input files: @example -##t ##f -#1 #-1.5 -#"this is a string" -#"this -is -a string" +#(define (average a b c) (/ (+ a b c) 3)) @end example Note that LilyPond comments (@code{%} and @code{%@{ %@}}) cannot -be used within Scheme code. Comments in Guile Scheme are entered +be used within Scheme code, even in a LilyPond input file, because +the Guile interpreter, not the LilyPond parser, is interpreting +the Scheme expression. Comments in Guile Scheme are entered as follows: @example @@ -517,9 +639,13 @@ as follows: !# @end example -Multiple consecutive scheme expressions in a music file can be -combined using the @code{begin} operator. This permits the number -of hash marks to be reduced to one. +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 +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 +@code{begin} statement: @example #(begin @@ -527,39 +653,34 @@ of hash marks to be reduced to one. (define bar 1)) @end example -@c todo -- # introduces a scheme *expression* -@c need the concept of an expression - -If @code{#} is followed by an opening parenthesis, @code{(}, as in -the example above, the parser will remain in Scheme mode until -a matching closing parenthesis, @code{)}, is found, so further -@code{#} symbols to introduce a Scheme section are not required. - -For the rest of this section, we will assume that the data is entered -in a music file, so we add @code{#}s everywhere. @node LilyPond variables @subsection LilyPond variables - -TODO -- make this read right - -A similar thing -happens with variables. After defining a variable +LilyPond variables are stored internally in the form of Scheme +variables. Thus, @example twelve = 12 @end example @noindent -variables can also be used in expressions, here +is equivalent to @example -twentyFour = (* 2 twelve) +#(define twelve 12) +@end example + +This means that LilyPond variables are available +for use in Scheme expressions. For example, we could use + +@example +twentyFour = #(* 2 twelve) @end example @noindent -the number 24 is stored in the variable @code{twentyFour}. +which would result in the number 24 being stored in the +LilyPond (and Scheme) variable @code{twentyFour}. @node Input variables and Scheme @subsection Input variables and Scheme @@ -577,10 +698,12 @@ traLaLa = @{ c'4 d'4 @} There is also a form of scoping: in the following example, the @code{\layout} block also contains a @code{traLaLa} variable, which is independent of the outer @code{\traLaLa}. + @example traLaLa = @{ c'4 d'4 @} \layout @{ traLaLa = 1.0 @} @end example + @c In effect, each input file is a scope, and all @code{\header}, @code{\midi}, and @code{\layout} blocks are scopes nested inside that @@ -588,18 +711,20 @@ toplevel scope. Both variables and scoping are implemented in the GUILE module system. An anonymous Scheme module is attached to each scope. An assignment of -the form +the form: + @example traLaLa = @{ c'4 d'4 @} @end example @noindent -is internally converted to a Scheme definition +is internally converted to a Scheme definition: + @example (define traLaLa @var{Scheme value of `@code{... }'}) @end example -This means that input variables and Scheme variables may be freely +This means that LilyPond variables and Scheme variables may be freely mixed. In the following example, a music fragment is stored in the variable @code{traLaLa}, and duplicated using Scheme. The result is imported in a @code{\score} block by means of a second variable @@ -641,7 +766,7 @@ been written as Scheme code is evaluated as soon as the parser encounters it. To define some Scheme code in a macro (to be called later), use -@ref{Void functions}, or +@ref{Void scheme functions}, or @example #(define (nopc) @@ -655,24 +780,28 @@ define some Scheme code in a macro (to be called later), use @knownissues Mixing Scheme and LilyPond variables is not possible with the -@code{--safe} option. - - +@option{--safe} option. @node Object properties @subsection Object properties -This syntax will be used very frequently, since many of the layout -tweaks involve assigning (Scheme) values to internal variables, for -example +Object properties are stored in LilyPond in the form of alist-chains, +which are lists of alists. Properties are set by adding values at +the beginning of the property list. Properties are read by retrieving +values from the alists. + +Setting a new value for a property requires assigning a value to +the alist with both a key and a value. The LilyPond syntax for doing +this is: @example \override Stem #'thickness = #2.6 @end example -This instruction adjusts the appearance of stems. The value @code{2.6} -is put into the @code{thickness} variable of a @code{Stem} +This instruction adjusts the appearance of stems. An alist entry +@code{'(thickness . 2.6)} is added to the property list of the +@code{Stem} object. @code{thickness} is measured relative to the thickness of staff lines, so these stem lines will be @code{2.6} times the width of staff lines. This makes stems almost twice as thick as their @@ -680,7 +809,7 @@ normal size. To distinguish between variables defined in input files (like @code{twentyFour} in the example above) and variables of internal objects, we will call the latter @q{properties} and the former @q{variables.} So, the stem object has a @code{thickness} property, -while @code{twentyFour} is an variable. +while @code{twentyFour} is a variable. @cindex properties vs. variables @cindex variables vs. properties @@ -692,41 +821,70 @@ while @code{twentyFour} is an variable. @node LilyPond compound variables @subsection LilyPond compound variables -@unnumberedsubsubsec Offsets +@subheading Offsets -Two-dimensional offsets (X and Y coordinates) as well as object sizes -(intervals with a left and right point) are entered as @code{pairs}. A -pair@footnote{In Scheme terminology, the pair is called @code{cons}, -and its two elements are called @code{car} and @code{cdr} respectively.} -is entered as @code{(first . second)} and, like symbols, they must be quoted, +Two-dimensional offsets (X and Y coordinates) are stored as @code{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) @end example -This assigns the pair (1, 2) to the @code{extra-offset} property of the +This assigns the pair @code{(1 . 2)} to the @code{extra-offset} +property of the TextScript object. These numbers are measured in staff-spaces, so this command moves the object 1 staff space to the right, and 2 spaces up. -@unnumberedsubsubsec Extents +Procedures for working with offsets are found in @file{scm/lily-library.scm}. + +@subheading 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}). +Intervals are used to store the X- and Y- extents of printable objects. +For X extents, the @code{car} is the left hand X coordinate, and the +@code{cdr} is the right hand X coordinate. For Y extents, the @code{car} +is the bottom coordinate, and the @code{cdr} is the top coordinate. + +Procedures for working with intervals are found in +@file{scm/lily-library.scm}. These procedures should be used when possible +to ensure consistency of code. + +@subheading Property alists -todo -- write something about extents +A property alist is a LilyPond data structure that is an alist whose +keys are properties and whose values are Scheme expressions that give +the desired value for the property. -@unnumberedsubsubsec Property alists +LilyPond properties are Scheme symbols, such as @code{'thickness}. -todo -- write something about property alists +@subheading Alist chains -@unnumberedsubsubsec Alist chains +An alist chain is a list containing property alists. -todo -- write something about alist chains +The set of all properties that will apply to a grob is typically +stored as an alist chain. In order to find the value for a particular +property that a grob should have, each alist in the chain is searched in +order, looking for an entry containing the property key. The first alist +entry found is returned, and the value is the property value. + +The Scheme procedure @code{chain-assoc-get} is normally used to get +grob property values. @node Internal music representation @subsection Internal music representation +Internally, music is represented as a Scheme list. The list contains +various elements that affect the printed output. Parsing is the process +of converting music from the LilyPond input representation to the +internal Scheme representation. + When a music expression is parsed, it is converted into a set of Scheme music objects. The defining property of a music object is that -it takes up time. Time is a rational number that measures the length -of a piece of music in whole notes. +it takes up time. The time it takes up is called its @emph{duration}. +Durations are expressed as a rational number that measures the length +of the music object in whole notes. A music object has three kinds of types: @itemize @@ -779,7 +937,6 @@ to create complicated music functions. * Adding articulation to notes (example):: @end menu - @node Displaying music expressions @subsection Displaying music expressions @@ -830,8 +987,7 @@ a file. lilypond file.ly >display.txt @end example -With a bit of reformatting, the above information is -easier to read, +With a bit of reformatting, the above information is easier to read, @example (make-music 'SequentialMusic @@ -850,10 +1006,18 @@ containing a @code{NoteEvent} object (storing the duration and pitch properties) and any extra information (in this case, an @code{AbsoluteDynamicEvent} with a @code{"f"} text property. +@funindex{\void} +@code{\displayMusic} returns the music it displays, so it will get +interpreted as well as displayed. To avoid interpretation, write +@code{\void} before @code{\displayMusic}. @node Music properties @subsection Music properties +TODO -- make sure we delineate between @emph{music} properties, +@emph{context} properties, and @emph{layout} properties. These +are potentially confusing. + The @code{NoteEvent} object is the first object of the @code{'elements} property of @code{someNote}. @@ -975,7 +1139,7 @@ Now we examine the input, @end example So in our function, we need to clone this expression (so that we -have two notes to build the sequence), add @code{SlurEvents} to the +have two notes to build the sequence), add a @code{SlurEvent} to the @code{'elements} property of each one, and finally make a @code{SequentialMusic} with the two @code{EventChords}. @@ -1167,14 +1331,13 @@ We may verify that this music function works correctly, - @ignore @menu * Tweaking with Scheme:: @end menu -@c @node Tweaking with Scheme -@c @section Tweaking with Scheme +@c @nod e Tweaking with Scheme +@c @sectio n Tweaking with Scheme We have seen how LilyPond output can be heavily modified using commands like