One of the unique features of Jabka is that it provides for programmable model building. The programming language used is a subset of the Scheme programming language, which is a popular dialect of the language LISP. For Jabka, Scheme has been extended somewhat with the addition of two new data types that we call objects and transforms. This document gives a very brief introduction to the syntax of Jabka's subset of standard Scheme, and the features of standard Scheme that are included in Jabka. The document Jabka Object System details the special object oriented features for Jabka, and the document Jabka Graphics Programming Reference describes the features added to the language to support three dimensional graphics.
The Scheme language has a very simple syntax to remember, but the simplicity is deceptive -- it is also a very powerful language. The first thing to know about Scheme, particularly if you are used to languages like Pascal or C, is that the language is based on invoking functions, rather than issuing commands. What this means is that every time you perform an action in Scheme, a value is calculated and returned to you as an answer. For example, the statement (+ 1 2) means to add 1 and 2, returning their sum as the result of the statement. The answer is obviously 3, so we say that (+ 1 2) evaluates to 3, or that it has the value 3. Another way of thinking about this, is that nearly anywhere in a Scheme program where you might want to use the value 3, you could also use (+ 1 2). It may not be clear yet, what the advantage of this is, but be patient -- we will get there!
The example we have been using above will also serve to illustrate the syntax of Scheme. The entities from which Scheme is constructed are all known as S-expressions. These come in two basic types, atoms and lists.
An atom is the simplest Scheme entity. The four main types of atom you can use in Scheme are numbers, symbols, variables, and booleans. In the Jabka extensions to Scheme there are also transforms and objects, but these are discussed in a different document, the Jabka Object System. Numbers are easy, they just look like what you would expect. Examples are 2, 2.4, and -10.375. Sometimes, for extremely large or small numbers it becomes necessary to use scientific notation. This is done by using the letter e as part of the number to signify "times 10 to the ... power". For example, 1.3e5 stands for 130,000, or 1.3 x 10^5. Symbols are just words that stand for themselves, i.e. they have no numeric or other value. A symbol is written as any string of characters. For example tiger is a valid symbol, as are *-of-stage-and-screen, and 2-by-4. Note that symbols do not have to be alphabetic, but it is not permitted to use any of Scheme's syntax defining characters, like ' ( or ) as part of a symbol. Symbols may be used simply as a way of referring to some unique piece of information, or for giving names to things. Variables are the things that symbols name. A variable is simply a named entity, whose name is a Scheme symbol and whose value is some other Scheme entity. For example, the symbol cento might be used to name a variable whose value is 100. If this is so, we say that the value of cento is 100. Booleans are simply atoms that stand for true and false. The Scheme entity that stands for true is #t, and the one for false is #f. That's about all you need to know about booleans, except that there is also a special atom known as the empty list, that is written simply (). The empty list and #f are used interchangeably -- i.e. they are really two different names for the same thing. In making tests for truth or falsehood, an expression that evaluates to anything other than the empty list is considered true, and one that evaluates to the empty list is considered false. Numbers, symbols, booleans, and the empty list simply need to be used in order to exist in Scheme, i.e. nothing special needs to be done to create them. Variables, however, must be created and given values before being used. The command define is used to create a variable and give it its initial value. For example: (define cento 100) creates a variable named cento, and gives it the value 100. Later on, the value of this variable can be changed with the command set!. For example: (set! cento 50) changes the value of cento from 100 to 50.
A list is constructed from atoms and/or other lists, using parentheses to group the items together, and spaces to separate them. For example (+ 1 2) is a list. It begins with a left parenthesis, ends with a right parenthesis, and contains 3 S-expressions as its elements: a variable named +, the number 1, and the number 2. Lists can get quite complex, like ((all the) ((tea in china) (and in sri-lanka))) which is a list that has as elements two other lists. The first of these is (all the), and the second is ((tea in china) (and in sri-lanka)). The second list in turn has two elements that are themselves lists. This nesting of lists within lists can go on to an arbitrary level. Lists serve two important purposes in Scheme -- the first of these is to store information in a structured, organized way; and the second of these is to specify commands. The parts of lists have special names that you will find to be annoyingly meaningless. The first element of a list is called the car of the list, and the list you are left with after removing a list's car is called the cdr (it rhymes with udder) of the list. There is a historical reason why the names are so strange -- ask a computer science folklore junkie. For our purposes, just think of car as being first, and cdr as being rest and you won't get too confused. The empty list has neither a car nor a cdr . All other lists have both a car and a cdr. We call the process of joining the car and the cdr together to form a list cons (maybe that's short for construct). For example, the car of the list (+ 1 2) is +, and its cdr is (1 2). Conversely, to form the list (+ 1 2), cons together + and (1 2). For a more complex example, look at the "tea in china" list above. What are its car, and its cdr? If you got that easily, then what is the cdr of its car? Just as a check, the answers are (all the), (((tea in china) (and in sri-lanka))), and (the) -- yes, all the parentheses are correct and need to be there.
A Scheme command is simply a list. What makes it a command is just that it is evaluated in a very particular way -- its first element names or evaluates to a function or procedure to be executed, and the rest of the elements are interpreted as the function's arguments. When using Jabka, you tell Scheme to evaluate a command in one of two ways. For single commands, the simplest way is to place the cursor just beyond the closing parenthesis at the end of the command and press the enter key (line-feed if you are running Jabka under Emacs). To evaluate multiple commands on the Macintosh, the commands you wish to execute must first be selected by either dragging over them with the mouse or by using one of the Select options from the Edit menu. If under Emacs, make the selected region the command you wish to execute and use Esc C-z. The format of a command is simple. Go back to the example above: (+ 1 2). When a list is evaluated, Scheme expects the first element in the list to evaluate to a function. For now, take that to mean that the first element in the list must either be the name of one of Scheme's predefined functions, or the name of a function you yourself have constructed elsewhere in the program (see the define function below). In our example, the first thing in the list is +. + happens to be the name of Scheme's predefined function for doing addition (you guessed it!). All of the rest of the elements of the list are used as arguments to the function. First, each of the arguments in turn is evaluated to determine its value, the results are placed in a list, and finally the function signified by the first element of the list is applied to the list of arguments. In our example above, the process is simple: 1 and 2 are evaluated to determine their values, which are simply 1 and 2; these values are placed in a list (1 2), and finally the function + is applied to this list. (What + does is to simply add up all of the elements of the list.) The value of the function is returned as the value of the command, which will be 3 in this case. Test your understanding. What do you think the following command evaluates to? (+ (+ 1 2) (- 4 2)) Remember, first evaluate each of the arguments and place them in a list, then apply the function represented by the first element in the original list to this list of evaluated arguments. Follow this same process when evaluating each argument that is itself a list. Your answer should be 5.
You will soon find that it is often necessary to have arguments that do not have atomic values, but that are lists. The quote function provides the ability to tell Scheme that when interpreting an argument, it should not be evaluated but simply returned "as is". For example: (quote (+ 1 2)) returns as its value the list (+ 1 2). Note that the argument list (+ 1 2) is not evaluated. The quote function can be abbreviated by placing a single quotation-mark in front of the item that you do not want to be evaluated. For example, although (+ 1 2) is evaluated to return the value 3, whereas '(+ 1 2) returns the value (+ 1 2). At this point you may want to consider again the difference between symbols and variables. A name can be used purely as a symbol by simply placing a quote mark in front of it. Then, when evaluated it returns itself rather than an associated value. If we use our cento example from above, we say that the value of 'cento is cento, the value of cento is 100, and the value of 100 is 100.
The following procedures, functions, data types and definitions are mostly a subset of what is considered standard in Scheme and are provided in Jabka's Scheme. (Note for those familiar with other versions of Scheme: within Jabka there is no support for numeric types except limited-precision real numbers; and there is no support for characters, strings, vectors, or ports.) The following notation is used in the definitions below. Function definitions are given in a typewriter font, argument names are chosen to, as much as possible, indicate the required type of the arguments, and ... indicates that the prior type of argument may be repeated any number of times. Each function definition is followed by one or more examples. An example usually consists of a function call, followed by the symbol ==>, followed by an S-expression. This indicates that the call would return the value to the right of the arrow. We emphasize again, that the empty list () and #f may be used interchangebly. When Jabka prints the value #f it prints it as (). We use #f below when a boolean value is to be indicated, and () when a list structure is to be indicated.
examples: 6 6.0 -6.0 6.0e4 6.0e-4
(number? value) Returns #t if the argument evaluates to a number, #f otherwise. examples: (number? 16) ==> #t, (number? 'hello) ==> #f
(+ number1 number2 ...) All arguments must evaluate to numbers. Returns the sum of all of the arguments. examples: (+ 1 2) ==> 3, (+ 1 2 3 4 5) ==> 15
(- number1 number2 ...) All arguments must evaluate to numbers. Returns the difference obtained by subtracting the second and all further arguments from the first argument. Optionally, if only one argument is supplied, its negation is returned. examples: (- 2) ==> -2, (- 2 1) ==> 1 (- 5 4 3 2 1) ==> -5
(* number1 number2 ...) All arguments must evaluate to numbers. Returns the product of all of the arguments. examples: (* 2 3) ==> 6, (* 2 3 4 5) ==> 120
(/ number1 number2 ...) All arguments must evaluate to numbers. Returns the quotient obtained by dividing the second and all further arguments into the first argument. Optionally, if only one argument is supplied, its reciprocal is returned. examples: (/ 2) ==> 0.5, (/ 4 2)) ==> 2, (/ 5 4 3 2) ==> 0.208333
(= number1 number2) Both arguments must evaluate to numbers. Returns #t if the values of the arguments are numerically equal, #f otherwise. examples: (= 2 2) ==> #t, (= (+ 1 2) 2) ==> #f
(> number1 number2) Both arguments must evaluate to numbers. Returns #t if the value of the first argument is numerically greater than the second, #f otherwise. examples: (> 2 2) ==> #f, (> (+ 1 2) 2) ==> #t
(>= number1 number2) Both arguments must evaluate to numbers. Returns #t if the value of the first argument is numerically greater than or equal to the second, #f otherwise. examples: (>= 2 2) ==> #t (>= (+ 1 2) 2) ==> #t
(< number1 number2) Both arguments must evaluate to numbers. Returns #t if the value of the first argument is numerically less than the second, #f otherwise. examples: (< 2 2) ==> #f, (< (+ 1 2) 2) ==> #f
(<= number1 number2) Both arguments must evaluate to numbers. Returns #t if the value of the first argument is numerically greater than or equal to the second, #f otherwise. examples: (<= 2 2) ==> #t, (<= (+ 1 2) 2) ==> #f
pi This variable is predefined to have the value 3.14159265
(sin theta) The argument must evaluate to a number representing an angle in radians. Returns the trigonometric sine of the angle. examples: (sin 0) ==> 0 (sin (/ pi 2)) ==> 1
(cos theta) The argument must evaluate to a number representing an angle in radians. Returns the trigonometric cosine of the angle. examples: (cos 0) ==> 1, (cos (/ pi 2)) ==> 0
(tan theta) The argument must evaluate to a number representing an angle in radians. Returns the trigonometric tangent of the angle. examples: (tan 0) ==> 0, (tan (/ pi 2)) ==> large magnitude number with sign arbitrary
(atan rise run) The arguments must evaluate to numbers, and at least one of the arguments must be non-zero. The first of these is used as the length the side of a right triangle opposite an angle, the second as the side adjacent to the angle. Returns the angle in radians, in the range -pi to pi. examples: (atan 1 0) ==> 1.5708 i.e. pi/2, (atan 0 1) ==> 0 (atan 1 1) ==> 0.785398 i.e. pi/4
(radians angle) The argument must evaluate to a number representing an angle expressed in degrees. Returns the angle expressed in radians. example: (radians 45) ==> 0.785398 i.e. pi/4
(degrees angle) The argument must evaluate to a number representing an angle expressed in radians. Returns the angle expressed in degrees. example: (degrees (/ pi 4)) ==> 45
(sqrt value) The argument must evaluate to a positive number. Returns the square root of the number. example: (sqrt 4) ==> 2
(exp power) The argument must evaluate to a number. Returns e (the base of the natural logarithms) raised to this power. (exp 0) ==> 1, (expt 1) => 2.71828 i.e. e, (exp 2) ==> 7.38906 i.e. e squared
(log value) The argument must evaluate to a positive, non-zero number. Returns the natural logarithm of the argument. examples: (log 1) ==> 0, (log 7.38906) ==> 2
(expt base power) The first argument must evaluate to a positive number, the second argument to any number, and the arguments cannot both be zero. Returns the first argument raised to the power of the second argument. examples: (expt 4 0.5) ==> 2, (expt 4 -1) ==> 0.25, (expt 4 2) ==> 16
(floor value) The argument must evaluate to a number. Returns the greatest integer less-than or equal to the argument. examples: (floor 4.0) ==> 4, (floor 4.3) ==> 4, (floor -4.3) ==> -5
(ceil value) The argument must evaluate to a number. Returns the least integer greater-than or equal to the argument. examples: (ceil 4.0) ==> 4, (ceil 4.3) ==> 5, (ceil -4.3) ==> -4
(truncate value) The argument must evaluate to a number. Returns the integer part of the argument. examples: (truncate 4.0) ==> 4, (truncate 4.6) ==> 4, (truncate 4.3) ==> 4, (truncate -4.3) ==> -4
(round value) The argument must evaluate to a number. Returns the argument rounded to the nearest integer. examples: (round 4.0) ==> 4, (round 4.6) ==> 5, (round 4.3) ==> 4, (round -4.3) ==> -4
(abs value) The argument must evaluate to a number. Returns the absolute value of the argument. examples: (abs 5) ==> 5, (abs -5) ==> 5
(max value1 value2 ...) All arguments must evaluate to numbers. Returns the largest of all of the arguments. example: (max 2 10 4 -3 6) ==> 10
(min value1 value2 ...) All arguments must evaluate to numbers. Returns the smallest of all of the arguments. example: (max 2 10 4 -3 6) ==> -3
(rand) Returns a pseudo-random number between 0.0 and 1.0 inclusive. examples: (rand) ==> 0.513871 for example, (rand) ==> 0.175726 for another example, (rand) ==> 0.308634 for yet another example
(seed value) The argument must evaluate to a number. Establishes a unique starting point for a random sequence. Returns its argument. example: (seed 145) ==> 145 after making this call, a sequence of calls to (rand) will generate a specific pseudo-random sequence of values that happens to start with 0.51033. Later, if (seed 145) is called again, subsequent calls to (rand) will give the exact same sequence starting with 0.51033. This is handy if you want to regenerate an exact repetition of a seemingly random sequence.
examples: #t #f note again that #f, and the empty list () are identical entities
(eq? arg1 arg2) Returns #t if the two arguments evaluate to exactly the same entity, #f otherwise. examples: (eq? 'cow 'cow) ==> #t note: identical symbols are always eq?, (eq? 2 2) ==> #f note: that two numbers are not generally eq? even if they have the same values! See eqv? below.
(eqv? arg1 arg2) Returns #t if the two arguments are eq?, or they evaluate to atoms of the same value, #f otherwise. examples: (eq? 'cow 'cow) ==> #t, (eqv? 2 2) ==> #t note: two numbers are always eqv? if their values are equal!, (eqv? (+ 1 1) 2) ==> #t
(equal? arg1 arg2) Returns #t if the two arguments evaluate to two entities that are either eq?, eqv?, or have exactly the same structure, with eqv? values in matching places within the structures. examples: (equal? 'cow 'cow) ==> #t, (equal? 2 2) ==> #t, (equal? '(all the (tea in china)) '(all the (tea in china))) ==> #t, (equal? '(all the (tea in china)) '(all the (tea in burma))) ==> #f
(or expression1 expression2 ...) Evaluates the first argument. If it does not have a value of #f (or the empty list) then returns the value of this argument. Otherwise, repeats this process as needed for the second and further arguments. If all arguments are found to have a value of #f, returns #f. examples: (or (= 1 2) 'hot-dog (= 2 2)) ==> hot-dog, (or (> -1 1) (= 1 2)) ==> #f
(and expression1 expression2 ...) Evaluates the first argument. If it has a value of #f (or the empty list) then returns #f. Otherwise, repeats this process as needed for the second and further arguments. If no arguments are found to have a value of #f, returns the value of the last argument. examples: (and (= 1 1) 'hot-dog 6) ==> 6, (and (> -1 1) (= 1 1)) ==> #f
(not expression) Evaluates the argument. If it has a value of #f (or the empty list) then returns #t, otherwise returns #f. examples: (not (= 1 1)) ==> #f, (not (= -1 1)) ==> #t
examples: stand-by-me 2by4 *tiger*
(define name value) The first argument must be a symbol. Makes that symbol into a variable, by "binding" the evaluation of the second argument to the symbol as its value. Returns the variable's initial value. examples: (define x 14) ==> 14 creates variable x with value 14, (define hot-dog 'frank) ==> frank creates variable hot-dog with value frank note: examples below for symbol? and symbol-bound? refer to the two definitions above
(symbol? arg) Returns #t if the argument evaluates to a symbol, #f otherwise. examples: (symbol? x) ==> #f, (symbol? hot-dog) ==> #t (symbol? 'x) ==> #t
(symbol-bound? arg) The argument must evaluate to a symbol. Returns #t if the argument evaluates to a variable (i.e. a symbol with an associated value), #f otherwise. examples: (symbol-bound? x) ==> error since x does not evaluate to a symbol!, (symbol-bound? 'x) ==> #t, (symbol-bound? hot-dog) ==> #f assuming frank is not itself a variable (symbol-bound? 'hot-dog) ==> #t
(set! name value) The first argument must be the name of a previously defined variable. "Binds" the evaluation of the second argument to the variable as its value. Returns the new value. examples: (set! x 10) ==> 10 changes the value of x to 10, (set! hot-dog 'weiner) ==> 'weiner
examples: () (+ 1 2) (all (the tea (in china)))
(cons value list) The second argument must evaluate to a list. Returns a new list with the first argument as its car, and the second argument as its cdr. examples: (cons 10 '(a b)) ==> (10 a b), (cons 'hot-dog '()) ==> (hot-dog), (cons '(a b) '(c d e)) ==> ((a b) c d e)
(car list) The first argument must evaluate to a non-empty list. Returns the car of this list. examples: (car '(a b)) ==> a, (car '((hot-dog hamburger) french-fries)) ==> (hot-dog hamburger)
(cdr list) The first argument must evaluate to a non-empty list. Returns the cdr of this list. examples: (cdr '(a b)) ==> (b), (cdr '((hot-dog hamburger) french-fries)) ==> (french-fries), (cdr '(a)) ==> ()
(caar list), (cadr list), ..., (cdddar list), (cddddr list) There are 28 functions that look like this that are the compositions of car and cdr up to four deep. For example, (cadr list) returns the car of the cdr of the argument list. An a stands for a car operation, and a d stands for a cdr operation. The operations take place from right to left as the a's and d's appear in the function's name. examples: (cadr '(a b)) ==> b, (cdar '((hot-dog hamburger) french-fries)) ==> (hamburger)
(set-car! list value) The first argument must evaluate to a non-empty list. Sets the car of this list to the evaluation of the second argument. This procedure should be used with great caution, because it changes the actual list structure, and can have the side effect of changing other lists that share structure with the list being modified. Returns the new car. examples: (define x '(a b c)) ==> (a b c) x is now a variable with value (a b c), (set-car! x 'p) ==> p x now has the value (p b c)
(set-cdr! list1 list2) The first argument must evaluate to a non-empty list, and the second any list. Sets the cdr of the first list to the second list . This procedure should be used with great caution, because it changes the actual list structure, and can have the side effect of changing other lists that share structure with the list being modified. Returns the new cdr. examples: (define x '(a b c)) ==> (a b c) x is now a variable with value (a b c), (set-cdr! x '(q r)) ==> (q r) x now has the value (a q r)
(pair? list) Returns #t if the argument evaluates to a non-empty list, #f otherwise. examples: (pair? 2) ==> #f, (pair? '()) ==> #f, (pair? '(x y)) ==> #t
(null? list) Returns #t if the argument evaluates to the empty list, #f otherwise. examples: (null? 2) ==> #f, (null? '()) ==> #t, (null? '(x y)) ==> #f
(list value1 ...) Returns a list containing the evaluations of each of the arguments in the same order in which the arguments appear in the list. Note that this is different from quote since the arguments are all evaluated before the list is formed. examples: (list 2) ==> (2), (list (+ 1 2) (- 4 2)) ==> (3 2)
(length list) The argument must evaluate to a list. Returns the number of elements in the list. examples: (length '()) ==> 0, (length '(1 2 3)) ==> 3, (length '(all (the tea (in china)))) ==> 2 i.e. the list contains a symbol and a list
(append list1 list2 ...) All arguments must evaluate to lists. Returns a new list formed by removing the outer parentheses from each of these lists, concatenating the elements of the lists together, and enclosing this concatenation in parentheses. examples: (append '(1 2) '(3 4 5)) ==> (1 2 3 4 5), (append '(1 2 3) '()) ==> (1 2 3), (append '(all (the tea (in china))) '(and japan)) ==> (all (the tea (in china)) and japan)
(reverse list) The argument must evaluate to a list. Returns a list whose arguments are in reverse order from the original list. examples: (reverse '()) ==> (), (reverse '(1 2 3)) ==> (3 2 1), (reverse '(all (the tea (in china)))) ==> ((the tea (in china)) all)
(list-tail list k) The first argument must evaluate to a list, and the second to a positive integer number, k. Returns the empty list if the second argument is greater than or equal to the length of the list or negative, otherwise returns the original list with the first k elements removed. examples: (list-tail '(1 2 3) 1) ==> (2 3), (list-tail '(1 2 3) 3) ==> (), (list-tail '(all (the tea (in china))) 0) ==> (all (the tea (in china)))
(list-ref list k) The first argument must evaluate to a list, and the second to a positive integer number, k. Returns the empty list if the second argument is greater than or equal to the length of the list or negative, otherwise returns the kth element of the list with numbering starting at 0 from the left. This is exactly the car of (list-tail list k). examples: (list-ref '(1 2 3) 1) ==> 2, (list-ref '(1 2 3) 3) ==> (), (list-ref '(all (the tea (in china))) 0) ==> all
(last list) The first argument must evaluate to a non-empty list. Returns the last element of the list (sort of a backwards car). examples: (last '(1 2 3)) ==> 3, (last '(all (the tea (in china)))) ==> (the tea (in china))
(memq item list) The second argument must evaluate to a list. Searches this list to see if any of its elements is eq? the evaluation of the first argument. If a match is found, the portion of the list from the match over to the right is returned. If no match is found, the empty list is returned. examples: (memq 'us '(canada us mexico)) ==> (us mexico), (memq 3 '(1 2 3)) ==> (), since 3 is not eq? 3! (memq '(orange surprise) '(lemonade (orange surprise) (mint tea)) ==> ()
(memv item list) The second argument must evaluate to a list. Searches this list to see if any of its elements is eqv? the evaluation of the first argument. If a match is found, the portion of the list from the match over to the right is returned. If no match is found, the empty list is returned. examples: (memv 'us '(canada us mexico)) ==> (us mexico), (memv 3 '(1 2 3)) ==> (3), (memv '(orange surprise) '(lemonade (orange surprise) (mint tea)) ==> ()
(member item list) The second argument must evaluate to a list. Searches this list to see if any of its elements is equal? the evaluation of the first argument. If a match is found, the portion of the list from the match over to the right is returned. If no match is found, the empty list is returned. examples: (member 'us '(canada us mexico)) ==> (us mexico), (member 3 '(1 2 3)) ==> (3), (member '(orange surprise) '(lemonade (orange surprise) (mint tea)) ==> ((orange surprise) (mint tea))
The next three functions require an argument that is an association list. An association list is simply a list, each of whose elements is a two element list. An example would be: ((elephant big) (mouse small) (tiger fierce) (bunny cute))
(assq item alist) The second argument must evaluate to an association list. Searches the association list to see if the car of any of its elements is eq? to the evaluation of the first argument. If a match is found, the matching element is returned, otherwise the empty list is returned. examples: (assq 'cola '((root-beer 60) (cola 55) (spritzer 85))) ==> (cola 55), (assq 3 '((1 for-$) (2 for-show) (3 get-ready) (4 go-cat-go))) ==> (), (assq '(all (the tea)) '(((all (the tea)) (for me)) ((all (the coffee) (for you)))) ==> ()
(assv item alist) The second argument must evaluate to an association list. Searches the association list to see if the car of any of its elements is eqv? to the evaluation of the first argument. If a match is found, the matching element is returned, otherwise the empty list is returned. examples: (assv 'cola '((root-beer 60) (cola 55) (spritzer 85))) ==> (cola 55), (assv 3 '((1 for-$) (2 for-show) (3 get-ready) (4 go-cat-go))) ==> (3 get-ready), (assv '(all (the tea)) '(((all (the tea)) (for me)) ((all (the coffee) (for you)))) ==> ()
(assoc item alist) The second argument must evaluate to an association list. Searches the association list to see if the car of any of its elements is equal? to the evaluation of the first argument. If a match is found, the matching element is returned, otherwise the empty list is returned. examples: (assoc 'cola '((root-beer 60) (cola 55) (spritzer 85))) ==> (cola 55), (assoc 3 '((1 for-$) (2 for-show) (3 get-ready) (4 go-cat-go))) ==> (3 get-ready), (assoc '(all (the tea)) '(((all (the tea)) (for me)) ((all (the coffee) (for you)))) ==> ((all (the tea)) (for me))
(copy-list list) The argument must evaluate to a list. Returns a fresh copy of the list, that is guaranteed to equal? the original list. This procedure is handy when you want to use set-car! or set-cdr! on a list but don't want to accidentally change the contents of any other lists. examples: (copy-list '()) ==> (), (copy-list '(1 2 3)) ==> (1 2 3), (copy-list '(all (the tea (in china)))) ==> (all (the tea (in china)))
(define (function-name args) expression ...) This form of the define procedure is a convenient syntax for defining variables that name functions. The function-name argument must be a symbol -- it will become the variable that names the function being defined. args indicates the names of 0 or more arguments that the function is to take. The expression's are Scheme expressions that are to be evaluated in the order specified when the function being defined is evaluated. The value that will be returned by the newly defined function when it is evaluated is the value of the last expression evaluated in the function. define returns the newly formed function as an unnamed lambda expression. example: (define (not-zero x) (not (= x 0))) ==> #<CLOSURE (x) (not (= x 0))> Defines a function named not-zero that takes a single argument, and returns #t if the argument is a non-zero number, #f otherwise. Note, that a define that appears within the body of another define or within a let creates only local variables and/or functions that are in effect only within the body of the surrounding define or let.
(let local-definitions expression ...) The let procedure creates a local environment within which temporary local variables can be defined that may have the same names as other variables. The local variables will be used within the body of the let, and discarded when the let is complete -- this gives the user the ability to write procedures without worrying that variable names used only within the procedure will clash with variable names defined elsewhere. let returns as its value the value of the last expression evaluated within its body. local-definitions is an association list, where each element consists of a local variable name followed by its beginning value. example: (let ((a 1) (b 3)) (+ a b)) creates local variables a with value 1 and b with value 3, adds a and b together, and returns their sum, 4. Upon return, both of the local variables a and b are discarded.
(lambda args expression ...) Used to define new unnamed functions. args is a list of the names of 0 or more arguments that the function is to take. The expression's are Scheme expressions that are to be evaluated in the order specified when the function being defined is evaluated. The value that will be returned by the newly defined function when it is called is the value of the last expression evaluated in the function. example: (lambda (x) (not (= x 0))) Defines an unnamed function that takes a single argument, and returns #t if the argument is a non-zero number, #f otherwise.
(if test then-expression else-expression) Used when conditional evaluation of expressions is needed. test is evaluated -- if its value is true (i.e. not #f or the empty list) then the then-expression is evaluated, otherwise the else-expression is evaluated. The else-expression may be omitted, in which case the then-expression is either evaluated and its value is returned or skipped and #f is returned, depending on the value of test. examples: (define x 10) (define y 6) (if (= x y) (+ x 1) (+ y 1)) ==> 7, (if (> x y) (+ x 1) (+ y 1)) ==> 11, (if (= x y) (+ x 1)) ==> ()
(begin expression ...) Used to group expressions together in a block, for situations where a sequence of expression's must be evaluated to achieve a desired effect. begin evaluates each of its arguments in turn, and returns the evaluation of its last argument. example: (define x 10) (begin (print x) (set! x (+ x 1))) ==> prints the value 10, then returns 11. x is left with the value 11.
(apply function list) The first argument must evaluate to a function, and the second to a list. The function is simply applied to the list, treating the elements of the list as if they were the arguments to the function. The number of elements of the list must match the required number of arguments for the function. example: (apply + '(1 2)) ==> 3
(map function list) The first argument must evaluate to a function of exactly one argument, and the second argument must evaluate to a list. Returns a new list obtained by applying the function successively to each element of the original list and forming a list of the results. example: (map car '((a b c) (x y) (1 2))) ==> (a x 1)
(eval list environment) The first argument must evaluate to a list, and the second to an environment (frequently this argument will be (the-environment)). Returns the evaluation of the list. example: (eval '(+ 1 2) (the-environment)) ==> 3
(the-environment) Returns the environment currently in effect. We will use this mostly for eval above. example: (let ((x 1) (y 2)) (let ((z 3)) (the-environment))) ==> (((z) 3) ((x y) 1 2)) note: an environment consists of a list containing zero or more sublists. Each sublist contains as its car a list of the names of currently defined local variables, and its cdr the values of these variables. The lists in the environment are in reverse order of nesting, with the most recently defined local-variables first in the list.
(print expression) Evaluates the argument and displays its value in the output window. Returns #t. examples: (print 'hello-world) ==> #t and "hello-world" is displayed, (print (+ 1 2)) ==> #t and "3" is displayed
(load filename) The argument must evaluate to a symbol that corresponds with the name of a file containing Scheme code. Reads the code from the file, and evaluates each expression found. Stops if an error occurs in the code being evaluated. Returns #t if successful, #f otherwise. This is needed when you are running Jabka under a Unix shell is also handy when you are running Jabka under an interactive interface and want to evaluate the contents of an entire file, but do not care to see the contents of the file viewed in an editor window. examples: (load 'toad.scm) ==> #t assuming a file with the name "toad.scm" exists and contains a valid Jabka Scheme program, reads and executes each line of the file as if it were a scheme program.
(error message-symbol invalid-entity) The first argument must evaluate to a symbol. Stops the evaluation process, and produces an error message of the form -- ERROR: message-symbol (see errobj) and places the evaluation of the second argument into the variable errobj for later examination by the user. Returns nothing, since this procedure stops all evaluation. examples: (error "invalid argument to procedure" argname) ==> the error message ERROR: invalid argument to procedure (see errobj) is printed and evaluation stops.
(symbolconc symbol1 symbol2 ...) All arguments must evaluate to symbols. Returns a single new symbol obtained by concatenating all arguments together. examples: (symbolconc 'get '-it '-together) ==> get-it-together
Scheme has a fixed amount of space set aside for storing the various Scheme entities that get created when expressions are evaluated. When this space runs out, Scheme automatically does what is called garbage-collection. This consists of searching through all of the stored entities and discarding those that are no longer being used.
(gc-status verbose) Produces a message giving the total number of Scheme entities that are currently allocated, and how many spaces are left for further allocation. The argument is optional. If its is #f automatic reporting of garbage collections will be turned off (silent mode), if it is not #f automatic reporting of garbage collections will be turned on (verbose mode). If the argument is ommited, garbage collection reporting will be unchanged (it is normally verbose). This procedure is used mainly to satisfy curiosity.
(gc) Causes garbage collection to occur, freeing the space taken by Scheme entities that are allocated but no longer being used. This procedure is hardly ever used, since Scheme automatically garbage-collects whenever it is low on space.