Last update : April 23, 2015
The Scheme programmimg language is a dialect of Lisp designed to be more consistent. Originally specified in 1958, Lisp is the second-oldest high-level programming language; Fortran is one year older. Lisp has a distinctive, fully parenthesized Polish Notation. The name LISP derives from LISt Processing. All program code in Lisp is written as s-expressions, or parenthesized lists. Lots of brackets comes to most people’s mind when they look at s-expressions. Lisp was invented by John McCarthy in 1958 while he was at the Massachusetts Institute of Technology (MIT). Lisp became quickly the favored programming language for artificial intelligence (AI) research. Another dialect of Lisp is Common Lisp (CL).
Scheme was invented by Guy Lewis Steele Jr. and Gerald Jay Sussman. The Scheme language is standardized in the official IEEE standard and in a de facto standard called the Revisedn Report on the Algorithmic Language Scheme (RnRS). The latest standard R7RS was finalized in 2013. An improper list of Scheme resources is available at the schemers.org website.
The Festival TTS system uses an enhanced version of Scheme, based on George Carrette’s SIOD (Scheme in one Defun).
In Scheme, an expression is an atom or a list. Atoms can be symbols, numbers, strings or special types like functions, arrays, hash tables. A list consist of a left parenthesis, a number of expressions and a right parenthesis. Comments are started by a semicolon and run until end of line. Scheme is case sensitive.
Each member of a list (except set!) is evaluated. The 1st item is treated as function and applied using the remainder of the lists as arguments to the function. Strings are bounded by the double-quote character.
"This is a string with embedded \"...\" quotes"
Double quotes in a string are escaped with a backslash ( \ ).
Scheme Core Functions
The core functions are :
- (set! SYMBOL VALUE) ; attribute a value to a variable
- (define (FUNCNAME ARG0 ARG1 …) . BODY) ; declare the boy of a function with arguments
- (if TEST TRUECASE [FALSECASE] ) ; if the value of TEST is non-nil, return value of evaluated truecase-expression, otherwise, if present, return evaluated falsecase-expressionor nil
- (cond (TEST0 . BODY) (TEST1 . BODY) …) ; multipe if statement
- (begin . BODY) ; returns the value of the last s-expression in a list
- (or . DISJ) ; return the value of the 1st non-nil disjunct
- (and : CONJ) ; return the value of the 1st nil conjunct or the value of the last conjunct
- (car EXPR) ; return the 1st item of a list or nil for an atom or empty list
- (cdr EXPR) ; return the rest of a list or nil for an atom or empty list
- (cons EXPR0 EXPR1) ; build a new list with car of EXPR0 and crd of EXPR1
- (list . BODY) ; form a list from each of the arguments
- (append . BODY) ; join each of the arguments into a single list
- (nth N LIST) ; return Nth member of list (1st item is 0th member)
- (nth_cdr N LIST) ; return Nth cdr list
- (last LIST) ; return last crd of a list
- (reverse list) ; return the list in inverse order
- (member ITEM LIST) ; returns the cdr in LIST whose car is ITEM or nil if not found
- (assoc ITEM ALIST) ; standardlist format for representing value pairs
- (intern “abc”) ; convert a string to a symbol
- (parse-number “3.14”) ; convert a string to a number
- (mapcar fct list1 list2 …) ; returns a list which is the result of applying the function fcn to the elements of each of the lists specified
- (number? x) ; returns true if x is a number
- (symbol? x) ; returns true if x is a symbol
- (quote x) ; special form that returns x without evaluating it. Commonly written in abbreviated format as ‘x (apostrophe x = short hand for quote). The (quote something) form returns that something as itself no matter what the something is (symbol, list …). Self evaluated data like numbers and strings need not to be quoted.
If the 1st statement of a function is a string, it is treated as a documentation string. The string will be printed when help is requested for that function symbol. To request help, press the keys <Esc> and <h> simultaneously after entering the name of the function.
A Scheme s-expression is a construct that returns a value. Typical s-expressions are
3 ( 1 2 3) (a ( b c ) d) (( a b ) ( d e ))
Some examples of simple arithmetic scheme s-expressions are presented hereafter :
(+ 2 3 4) ; add the arguments (set! a 3) ; define the variable a to 3 (* a 5) ; multiply the arguments (/ 8 a) ; divide the 1st argument by the 2nd argument (- 12 a) ; substract the 2nd argument from the 1st argument (cons 1 2) ; join 2 arguments as a pair
The following figure shows the results :
Here are some more examples of scheme s-expressions :
; define a list with 3 fruits (set! fruits '(apples pears bananas)) ; use the 1st item of the list (car fruits) ; use the remaining items following the 1st item of the list (cdr fruits) ; define a list with 2 vegetables (set! vegetables '(carrots beans)) ; combine the fruit and vegetable lists (append fruits vegetables) ; get the number of items in the list (length fruits) ; get the number of items in the combined list (length (append fruits vegetables)) ; join 2 lists as a pair (cons vegetables fruits)
The next figure shows the results :
A regular expression is a sequence of characters that forms a search pattern, mainly for use in string matching (filters). A regular expression is sometimes called a rational expression and abbreviated as regex or regexp. The concept was formalized in the 1950s by the American mathematician Stephen Kleene who created a regular language. Today regular expressions are so useful in computing that the various systems to specify regular expressions have evolved to provide both a basic and extended standard for the grammar and syntax.
Festival Scheme uses a regex implementation based on Henry Spencer‘s regex code. In general all characters match themselves, except for the following ones which have special interpretations (meta-characters), if they are not preceded by a backslash :
. * + ? [ ] ( ) | ^ $ \
- . matches any character in the regex
- * matches zero or more occurences of the preceding item in the regex
- + matches one or more occurences of the preceding item in the regex
- ? matches zero or one occurence of the preceding item in the regex
- [ ] defines a range of characters
- ( ) defines a section (scope, block, capturing group)
- | or operator ; separates alternatives
- ^ if specified first negates the class
- $ matches the ending position of a string
- \ backslash to escape meta-characters
- a.c > abc, acc, adc
- a*c > c, aac, ac, aaaaaaaac
- a+c > ac, aaac
- ab?c > ac, abc
- [a-z] any lower case letter
- [a-zA-Z] any lower or upper case letter
- gr(e|a)y > grey, gray
- ^abc > any characters other than a, b or c
Scheme provides a special unique object called false, whose written representation is #f and who is the result of a condition expression (if or cond). This is the only value that counts as false, all others count as true. For this reason there is no need to provide a boolean object true, but for clarity, Scheme provides an object written #t which can be used as true value. In Festival’s Scheme (SIOD), #f and #t are unbound variables. In SIOD the variable t stands for true and nil stands for false.
Named and unnamed (anonymous = lambda) functions
Here is an example of a new (named) function :
(define (add a b) (+ a b)) (add 7 5)
Scheme provides a lot of useful string functions, for example
(string-equal ATOM1 ATOM2) (string-append STR1 STR2) (string-before STR SUBSTR) (string-after STR SUBSTR) (string-length SYMBOL) (string-matches STR REGEX) (Symbolexplode SYMBOL) (member_string STR LIST)
A function that returns either true (t) or false (nil) is called a predicate.
Instead of a named function, we can create unnamed (anonymous) functions using the special lambda form.
(lambda (arg1 arg2 ...) form1 form2 ...)
This function is simply defined where it’s used; for example, to square the items of a list we can apply the following construct
(set! mylist '(1 3 6 8)) (mapcar (lambda (x) (* x x)) mylist)
Scheme provides a very powerful nested conditional expression with the syntax
( cond < clause 1 > <c lause 2 > < clause 3 > ... )
where < clause > is of the form
( < predicate > < form > ...)
The last clause may be an else clause which has the syntax
( < else > < form 1> < form 2 > ...)
Cond is a special form where each clause is processed until the predicate expression of the clause evaluates true. Then each subform in the predicate is evaluated with the value of the last one becoming the value of the cond form.
A simple example is :
(cond (( > a b ) 'greater) (( < a b ) 'less) (t 'equal))
A more complex example is show hereafter :
(cond ((string-matches name "[1-9][0-9]+") (mbarnig_lb::number token name)) ((string-matches name "[A-Z]+") (mbarnig_lb::upper_case_abbr token name)) ((string-matches name "[a-z]+") (mbarnig_lb::lower_case_abbr token name)) (t (list name))) ; when no specific rules apply do the general ones
Another special conditional form is
(and subform1 subform2 subform3 ...)
This form causes the evaluation of its subforms in order, from left to right, continuing if and only if the subform returns a non-null value.
Here are some examples of scheme system commands :
(quit) or (exit) ; close the program
(pwd) ; show the pathname of the current directory
(setenv NAME VALUE)
(set_backtrace t) ; display a backtrace when a scheme error occurs
(unwind-protect …) ; catch errors and continue normally
A hook in Scheme terms is a position within the program code where a user may specify his own customization. There a number of places in Festival where hooks are used. A hook variable contains either a function or a list of functions that are to be applied at some point in the processing. A list of defined hooks in Festival is shown below :
- after_analysis_hooks : functions applied after analysis, before synthesis
- default_after_analysis_hooks : default functions applied after analysis
- before_synth_hooks : functions applied on synthesized utterances
- default_before_synth_hooks : default functions applied on synthesized utterances
- after_synth_hooks : functions applied after synthesis to manipulate waveforms
- default_after_synth_hooks : default functions applied after synthesis
- diphone_module_hooks : functions applied at the start of the diphone module
- tts_hooks : functions applied during text to speech
- xxml_hooks : functions applied before tts_hooks
- xxml_token_hooks : functions applied to each token
A list with links to websites providing additional informations about Scheme is provided hereafter :