User:Tinned Tuna

I am a software engineer from Hull, and an undergraduate student studying Computer Science and Mathematics at The University of York.

My current project is the Scheme Programming wikibook <!-- I plan to create a book on Scheme programming.

This will, hopefully, be the home of it until I work up the nerve to publish it to the 'real' WikiBooks. This is my first WikiBook. It will need clean up at a later date, etc.

Why Learn Scheme?
Scheme is an excellent language to learn the principles of most languages in. It's built with a small syntax, and abstracts the programmer far enough away from the machine to effectively express algorithms and ideas simply and concisely.

Why Scheme rather than Java, Python or another high-level language?
Java and Python are very powerful real world languages, but they often struggle as languages for learning, because of the extra syntax they have for enabling the programmer to easily access the more advanced features, but in doing so quickly complicate the whole matter, thus defeating the point of being easy to learn.

Using a Scheme interpreter.
On most Unix machines, 'scm' can be installed. This is a Scheme interpreter which adheres to R5RS very well. At the time of writing, I have no experience with other Scheme interpreters on other operating systems.

To invoke the interpreter, simply type 'scm' at the command line. It is common to write your programs into a text file using Vim or emacs, and then load them in using the 'load command': $ scm > (load "myFile.scm") >
 * 1) &lt;unspecified&gt;

A taste of Scheme
Like almost every single programming language out there, we might as well start out with the tried-and-true 'Hello, World!' Program. In Scheme, this is spectacularly easy. From the shell, invoke the scm interpreter, and enter (print "Hello, World!")

$ scm > (print "Hello, World!") Hello, World! >

Scheme datatypes.
Scheme has several datatypes, there are atomic datatypes and compound.

Atomic:
 * Numbers,
 * Symbols,
 * Strings.

Compound:
 * Pairs,
 * Lists,
 * Vectors,
 * Closures.

Most programmers will be familiar will most of those, or atleast have an idea of what they do, but a closure is more mysterious. In it's simplest form, it's a function, or procedure.

Simple Expressions
As we have already seen, Scheme expressions have the form: (&lt;Operation&gt; &lt;Operand 1&gt; ... &lt;Operand n&gt;)

However, much simpler expressions are possible; all of the following are valid Scheme expressions and will be evaluated by the interpreter.

> 3 3 > #t > 6+1i 6.0+1.0i > '(1 3 5) (1 3 5) > '(1 . ) (1) > #(1 3) > +
 * t
 * 1) (1 3)
 * 1) 

We have, in their respective order:


 * A number
 * A Boolean
 * A complex number (A number with and imaginary component)
 * A list
 * A pair
 * A vector.
 * A primitive procedure (I.e. something that scm can use in order to evaluate data)

Simple Maths
We can use combinations of the datatypes and primitive procedures to perform simple (and not so simple) caluclations using the scm interpreter:

> (+ 2 2) 4 > (* 2 8) 16 > (- 2 1) 1 > (/ 3 4) 0.75

These are, in order,


 * Addition
 * Multiplication
 * Subtraction
 * Division

Each of these expressions can be nested within one another, thus:

> (+ (* 2 4) (/ 3 4) (- 2 1) (+ 2 2)) 13.75

This shows 2 important things about Scheme expressions:


 * Scheme expressions can be nested, leading to an important concept, the Substitution Model.
 * Some procedures can take a variable number of arguments; we'll show how to do this later.

The first point is most important at this point.

The Substitution Model
The substitution model for computing expressions is one of the simplest and most powerful ways of thinking about scheme expressions. It can be regarded as the basis of a large portion of Scheme.

In order to understand the substitution model, I'll give you a simple example, the one given before, and work through it.

> (+ (* 2 4) (/ 3 4) (- 2 1) (+ 2 2))

In order to evaluate this, the scheme interpreter must evaluate every sub-expression, thus decomposing it to atomic datatypes and primitives:

> (+ 8 0.75 1 4) 13.75

This same model can be applied to extra layers of nesting.

> (* (+ 13 1) (+ (* 2 4) (/ 3 4) (- 2 1) (+ 2 2))) > (* (+ 13 1) (+ 8 0.75 1 4)) > (* 14 13.75) 192.5

The best way to think about this is as a basic algorithm.


 * 1) Has the expression any subexpressions?
 * 2) yes: Evaluate subexpressions using this algorithm
 * 3) no: Evaluate whole expression of primitives.

Trigonometric Functions
Scheme always uses radians for its internal representation of angles, so it's sine, cosine, tangent, arcsine, arccosine, and arctangent functions operate as such:

> (sin 0) 0.0 > (cos 0) 1.0 > (tan 0) 0.0 > (asin 1) 1.5707963267948965 > (acos 0) 1.5707963267948965 > (atan 1) 0.7853981633974483

Hyperbolic Functions
Scheme provides a number of hyperbolic functions, such as hyperbolic sine, cosine, tangent and their inverses.

> (sinh 0) 0.0 > (cosh 0) 1.0 > (tanh 1) 0.7615941559557649 > (asinh 0) 0.0 > (acosh 1) 0.0 > (atanh 0) 0.0

Raising a base to a power
Scheme provides the  function to raise a base to an exponent.

> (expt 2 10) 1024

Finding the Square root of a number
Scheme provides a  function for finding the square root of a number.

> (sqrt 2) 1.4142135623730951 > (expt 2 0.5) ; Note an ingenious way to find the n-th power of something! 1.4142135623730951

Exponential
Scheme provides a  function for raising base $$e$$ to a power:

> (exp 2) 7.3890560989306504

Logarithm
Scheme provides a  function for finding the natural logarithm of a number:

> (log 7.389056) 1.999999986611192

Note that there is no built-in procedure for finding any other base logarithm other than base $$e$$.

Rounding functions.
Scheme provides a set of functions for rounding a real number up, down or to the nearest integer:


 * - This returns the largest integer that is no larger than x.
 * - This returns the smallest integer that is no smaller than x.
 * - This returns the integer value closest to x that is no larger than the absolute value of x.
 * - This rounds value of x to the nearest integer as is usual in mathematics. Even when halfway between values.
 * - This returns the absolute value of x.

Number theoretic division
In order to perform mathematically exact divisions and accomplish tasks for number theorists, Scheme provides a small number of division specific functions:


 * - Calculates the remainder of dividing x into y:

> (remainder 5 4) 1 > (remainder -5 4) -1 > (remainder 5 -4) 1 > (remainder -5 -4) -1


 * - Calculates the modulo of x and y.

> (modulo 5 4) 1 > (modulo -5 4) 3 > (modulo 5 -4) -3 > (modulo -5 4) 3

There is clearly a difference between modulo and remainder, one of them not shown here is that remainder is the only on which will return an inexact value, and can take inexact arguments.

Using Variables
In order to make your program a little more dynamic, it is often necessary to declare a variable, there are 2 main ways of doing this, using. The difference between the two is simple once fully grasped.

For example, using define:

> (define x 2) > (* x 3) 6 > x 2

This shows that even once used, the variable  continues to exist, it is defined for all the see, use and (as we shall see later on) modify at will.

In general, the form of a define statement for a variable is as follows:

(define )

Now we will see the use of

> (let ((x 2) (y 4)) (* x y)) 8 > x > y
 * ERROR: "/usr/lib/scm/Iedline.scm": unbound variable: x
 * ERROR: "/usr/lib/scm/Iedline.scm": unbound variable: y

Notice here, how once the block of code has finished executing, the variables  and   are no longer accessible. This is a very bulky and slow way to do this at this point, but it allows for more elegant programs later.

In general, the form of a let statement is as follows:

(let ((var1 val1) ... (varn valn)) )

Conditionals
This is a very important part of any program, as it can allow your program to make decisions, based on simple rules and the data it is given. Almost all useful Scheme programs make use of conditional expressions. Whether deciding if a number is even or odd, or if two strings are equivalent, conditionals litter most Scheme programs, and are a core part of all Turing complete languages.

In order to tackle conditionals, we must understand relational, equivalence and Boolean logic expressions

Relational and Equivalence Expressions
These determine how one value relates to another, is x larger than y? Is x the same as y? And so on and so forth.


 * (< a b): #t if 'a' is strictly less than 'b', #f otherwise.
 * (<= a b): #t if 'a' is less than or equal to 'b', #f otherwise.
 * (> a b): #t if 'a' is strictly greater than 'b', #f otherwise.
 * (>= a b): #t if 'a' is greater than or equal to 'b', #f otherwise.
 * (equal? a b): #t if 'a' is exactly equal to 'b', #f otherwise.

Conditionals
Now we know how to compare variables with one another, we can start executing code based on this, using an  expression:

> (if (> 6 5) (+ x y) (- x y)) 11

This code is very simple to understand; if the first expression is #t (i.e. true), then evaluate the second expression, otherwise evaluate the third.

In general, an if expression has the form:

(if () () ()) -->