One of a series of tutorials about Scheme in general
and the Wraith Scheme interpreter in particular.
Copyright © 2011
Jay Reynolds Freeman,
all rights reserved.
Personal Web Site: http://JayReynoldsFreeman.com
The point of this tutorial is not that a Scheme interpreter makes a good calculator. I don't think it does -- I myself would rather use one that has a fancy graphical user interface with lots of nice buttons to push. Notwithstanding, it might be easy to learn how Scheme works while you are using procedures that do familiar things, like common arithmetic and mathematical operations.
Incidentally, you don't have to be a "math type" to use Scheme. This tutorial briefly mentions some fairly advanced mathematical procedures, but you don't need to know about them, or to learn about them, in order to use the tutorial, or in order to use Scheme.
The typed-out pieces of text that represent the uses of Scheme procedures have a very uniform syntax: Every one of them starts with a left parenthesis, ends with a right parenthesis, and has one or more things in between. Here are a few:
(+ 2 2) (* 5 3) (sqrt 2)
The first adds two and two, the second multiplies five by three, and the third calculates the square root of two. All of these pieces of typed text represent procedure applications.
Every procedure application returns a result -- the result obtained when the procedure is applied to its arguments. Thus if you type the examples above into Wraith Scheme, or cut-and-paste or drag them in, they will yield "4", "15", and "1.4142135623730951", respectively, and those results will be displayed in the Main Display Panel. Try it and see. If you paste or drag, be sure you are aiming at the Input Panel. Furthermore, remember that Wraith Scheme doesn't "see" things you put there unless you provide a "newline" character, either in the pasted or dragged text itself or by typing "return" at the keyboard.
The preceding examples will probably make you suspect that every Scheme procedure application starts with a procedure, and is followed by the procedure's arguments. That is in fact correct. Scheme is boringly uniform about the syntax of procedure applications. The first thing inside the parentheses always evaluates to the Scheme object which does the work of the procedure: Typically, it is the name of the procedure, something like "+", "*", or "sqrt". All the rest of the in-between things are evaluated too, but that is not obvious in the examples above, because numbers always evaluate to themselves. In any case, after evaluation, all the rest of the things are passed to the procedure, as its arguments. That process is the same for every Scheme procedure application, not just the ones for arithmetic and other mathematical operations.
The bit about the rest of the in-between things getting evaluated makes more sense when they themselves are procedure applications. Consider the following:
(+ (* 3 3) (* 4 4))
The "+" just inside the first left parenthesis tells you that this is a procedure application that does addition, but each of the arguments is itself a procedure application. The first argument is "(* 3 3)", which evaluates to 9, and the second is "(* 4 4)", which evaluates to 16. Thus the "add" procedure gets 9 and 16 as arguments, and so returns 25. Type it in and try it.
This process can go on indefinitely. Let's wrap a square-root procedure application around the last example.
(sqrt (+ (* 3 3) (* 4 4)))
The 25 returned from the add procedure will be passed to the square-root procedure, so that what gets displayed in the Main Display Panel will be "5".
Different procedures take different numbers of arguments, and some individual procedures can take variable numbers of arguments. For example, the square-root procedure, "sqrt", always takes one argument, but the add and multiply procedures can take any number of arguments, including none at all. With these procedures, you can probably guess what happens with two or more arguments: The add procedure adds them all up, and the multiply procedure multiplies them all together. So for example
(+ 1 2 3 4 5)
returns 15, and
(* 1 2 3 4 5)
With just one argument, "+" and "*" return the argument itself. Thus
both return 42.
What about no arguments? It turns out that
returns 0, and
I am not sure that the behavior of these operations with one argument and with no arguments is intuitive, but it makes a certain sense, and is sometimes useful in writing programs. If you are sufficiently used to the conventions of regular arithmetic that what Scheme does with "(+)" and "(*)" is confusing you, you can perhaps make sense of it by imagining that every application of "+" includes a couple of invisible extra arguments whose value is zero, and that every application of "*" includes a couple of invisible extra arguments whose value is one. (That's not actually how the procedures are written, but it might help you remember what they do.) The invisible zeros and ones won't matter when there are other arguments -- you can add in as many extra zeros as you like, or multiply in as many extra ones as you like, without changing the arithmetic.
The procedures for subtraction and division are named "-" and "/", respectively. They both require at least one argument. With one argument, "-" returns the negative of the argument, and "/" returns its reciprocal. Try it and see, and do see what happens when you try to take the reciprocal of zero.
With two arguments, "-" subtracts the second from the first, and "/" divides the first by the second. Thus
(- 5 3)
(/ 5 3)
return 2 and 1.6666666666666667 respectively.
With more than two arguments, the behavior is again perhaps not intuitive, but again makes sense of a sort. The "-" procedure subtracts from the first argument the sum of all the rest, and the "/" procedure divides the first argument by the product of all the rest. Thus
(- 20 1 2 3)
returns 14, which is the same value that is returned by
(- 20 (+ 1 2 3))
(/ 20 1 2 3)
returns 3.3333333333333335, which is the same value that is returned by
(/ 20 (* 1 2 3))
That takes care of the basic four arithmetic operations, and I have also mentioned "sqrt", but there are a generous handful more. I will give an overview of them here, but for nitty-gritty details, refer to the Wraith Scheme Dictionary.
The "exp" procedure takes one argument, and exponentiates it -- that is, it returns e to the power which is its argument, e being the base of the natural logarithms, approximately 2.7182818284590451. For example,
Take care not to confuse "exp" with the very similarly named "expt": The latter procedure raises a number to a power -- it takes two arguments, and returns the first raised to the second. Thus
(expt 2 5)
returns 32 (that is, two to the fifth power is 32), and
(expt 2 128)
returns 3.4028236692093846e38 (and the "e38" demonstrates one way to provide a Scheme number with an exponent).
Scheme does not have a standard procedure for taking logarithms to the base ten: It does have a "log" procedure, but in Scheme, "log" takes the natural logarithm of its single argument; that is, the log to the base e. So for example
Incidentally, the arguments to all these procedures do not have to be integers. I have been using integers simply to make the examples easier to read.
Scheme does trigonometry. Procedures "sin", "cos", and "tan" each take one argument -- interpreted as an angle in radians, not degrees -- and do what you would expect. Their inverse procedures, "asin", "acos", and "atan", also do what you would probably expect (see the Wraith Scheme Dictionary to make sure), and return an angle in radians, but there is one exception: The "atan" procedure may also take two arguments. When it does, they are interpreted as the y coordinate (first argument) and x coordinate (second argument) of a point in the Cartesian plane, and the returned value is the angle from the positive x-axis to that point.
Wraith Scheme supports complex numbers with nonzero imaginary part. (Complex numbers are an optional part of R5 Scheme, so not all implementations will have them.) Thus for example
returns +i, and
(exp (* +i 3.1415926535897931))
returns -1.+1.2246467991473532e-16i (that is, "minus one plus 1.2246467991473532e-16 times i"), which is indeed very close to the exact value of -1 which we expect for e raised to the power (i times pi).
Note in passing that there are a few "gotchas" in typing complex numbers in Scheme. There is a whole separate tutorial about numbers, but I will list a few here. First, you may not include white space in a complex number: Even though it might be typographically desirable to type
2 + 3i
Scheme will not recognize that as a complex number -- what you must type is
Second, "i" by itself is not a number -- it is potentially a variable name. Use "+i" instead. That is why the preceding example was written as
(exp (* +i 3.1415926535897931))
(exp (* i 3.1415926535897931))
The latter form will not work.
Some mathematical procedures work only with particular kinds of numbers. Thus "ceiling", "floor", "round" and "truncate" each take a single argument which must be a real number, and return an integer obtained in the appropriate manner. (Remember that you can look things up in the Wraith Scheme Dictionary.) Procedures "min" and "max" each take two or more real numbers as arguments, and respectively return the minimum and maximum of their arguments. Procedure "abs" takes one real and returns its absolute value.
Procedures "gcd" and "lcm" each take one or more integer arguments and respectively return the greatest common divisor and the least common multiple of their arguments. Procedures "quotient" and "remainder" each take two integers. The former does integer division and the latter calculates the remainder when integer division is performed. Thus
(quotient 19 4)
returns 4, and
(remainder 19 4)
returns 3. The "modulo" procedure takes two integers, and returns its first argument modulo its second; the difference between "modulo" and "remainder" has to do with the sign of the result.
Several Scheme procedures are for working with complex numbers with nonzero imaginary part. You can create such numbers with "make-rectangular" and "make-polar":
(make-rectangular 3 4)
returns 3+4i, and
(make-polar 5 1.5707963267948966)
returns 3.0616169978683831e-16+5.i. (The first argument is the magnitude of the complex, the second is its angle.)
Speaking of "magnitude" and "angle", procedures of those names recover the magnitude and angle of a complex:
returns 1.5707963267948966, and
Finally, "real-part" and "imag-part" respectively return the real and imaginary parts of a complex number.
Scheme has many more procedures that deal with numbers; for example, this tutorial doesn't mention predicates -- ways to compare numbers for things like equality, greater-than, and so on, or to test a number to see whether it is zero not. Also, there are a few numeric procedures that Wraith Scheme provides as enhancements, that are not part of the "R5" standard. Finally, the discussion above has glossed over some of the fine points of the procedures mentioned, like which of the possible angles are returned by the inverse trigonometric procedures: For that level of detail, see the Wraith Scheme Dictionary or the R5 report. Yet by now you have learned a little about most of the arithmetic and mathematical procedures that Wraith Scheme provides, and I hope you have learned a little more about Scheme itself in the process.
-- Jay Reynolds Freeman (Jay_Reynolds_Freeman@mac.com)