Troubleshooters.Com, Code Corner, Steve's Scheme Society Present:

Scheme at a Glance

See the Troubleshooters.Com Bookstore.

CONTENTS

Introduction

This page moves you from zero Scheme knowledge to beginner level Scheme knowledge. To help the former C, C++, Java, Perl, Python, Ruby or Pascal programmer, there are a few references to similarities and differences between those languages and Scheme.

Because of Scheme's syntactic consistency, once you get used to the profusion of parentheses, this language actually turns out to be easy to learn and remember.

Hello World

The following is the a "Hello World" Scheme program, run with GNU Guile, as is all code on this page:

#!/usr/bin/env -S guile -s
!#
(display "Hello World")
(newline)

Notice the reverse shebang (!#) on line 2. That's because in Scheme, any code starting with #! and ending in !# is a comment, so the top shebang line must be followed by the !# comment-end string.

But wait, there's more! Consider the top line's command:

/usr/bin/env -S guile -s

The preceding is the most portable way to code a shebang line (#!), given that different computers have Guile binaries in different locations. By using /usr/bin/env you access it via the executable path rather than via a hard coded location. For more info, including the meaning of the -S argument to env, see the env man page.

We discussed Scheme's multiline comments bracketed by #! and !#. Scheme also has a linewise comment, the semicolon (;). Anything between an unquoted, unescaped semicolon and the end of the line is a comment in Scheme.

Define

In Scheme, you declare and instantiate a variable with the define function:

#!/usr/bin/env -S guile -s
!#
(define hi "Hello World")
(display hi)
(newline)

You just declared and instantiated a variable called hi. Variables declared with define are global variables. Local variables can be created with the let operator, as will be shown later. Once the variable is declared with define, further changes can be made using the set! operator, as will be shown later.

Notice that every Scheme statement occurs between parentheses. It takes a little getting used to, but that's how Scheme works. Every Scheme statement looks like this:

(operator operand operand ...)

The number of operands is defined by the operator. Operator define takes two operands, the variable name and the value being assigned it. The display operator takes one operand, the object to be printed on the screen. The newline operator takes no operands. Some operands, such as the append operand for lists, which will be demonstrated later in this document, takes an  indefinite number of operands.

This "operator comes first" syntax makes Scheme a "prefix language", because the operator is a prefix to the operands. Consider the following three ways of adding 3 and 7, remembering that Scheme is a prefix language:

Prefix
language
C like
language
Reverse
Polish
Notation
+ 3 73 + 73 7 +

When you get right down to it, operators are just subroutines, also known as procedures, functions and the like. You can easily code your own operators, as will be shown later in this document.

Arithmetic

Arithmetic is performed by operators such as +, -, *, /, modulo, as well as all sorts of trig, log and other functions. Scheme is especially good at math and arithmetic. Its calculations are arbitrary precision and extremely fast. I used Scheme (Guile implementation) to calculate 10,000 factorial in less than a fifth of a second.

But for now let's get back to basics. The following program adds 3 and 4:

#!/usr/bin/guile
!#

(display (+ 3 4))
(newline)

The preceding adds 3 and 4 to print 7. This shows that Scheme is a prefix language, meaning that in a statement, the operator comes first. Contrast this to C, Perl, Java etc where the operator comes between the operands, or Reverse Polish Notation, where the operator comes after the operands.

As you can see in the preceding code, we add 3 and 4 like this:

(+ 3 4)

So a Scheme statement starts with an operator, and then operands. When dealing with a procedure or function, the operator is the function, and the operands are the arguments to that function. Take the following code:

#!/usr/bin/guile
!#

(define hypotinuse
   (lambda(a b)
         (sqrt (+(* a a) (* b b)))
   )
)
            
(display (hypotinuse 1 1))
(newline)
(display (hypotinuse 3 4))
(newline)

In the preceding, hypotinuse, the programmer-defined function, is the operator, while 1 and 1, and later 3 and 4, are the operands. The operand comes first.

One more thing to notice. The statement inside any pair of parentheses returns a value, and that value is used in the calculation of the next outward set of parentheses. It makes one-liners very easy. Take a look at the single calculation line inside function hypotinuse. The squares are the innermost parenthese sets. The sum of those squares is the next level out. The square root of the sum of the squares is the next set out from there, and indeed the outermost parentheses in the calculation.

If Statement Basics

If statements will be discussed in detail later in this document, but before discussing subroutines, if statement basics must be discussed.

If is an operator taking exactly three arguments:

(if   condition   do_if_true   do_if_false)

The following is a very simple implementation:

(if (< number 0)                   ; if operator and condition
  (display "Number is negative.")     ; do if true
  (display "Number is non-negative.") ; do if false
)                                     ; end of if statement

Usually the do if true and do if false will involve several statements, in which case you'll make a compound statement using the begin operator, which can take any number of arguments. Compound statements are handled in the next article.

Compound Statements

Sometimes you want to put several statements together into one. For instance, if statements in C require exactly one statement after the condition, and yet you might want to do several different things. So in C you use curly braces to put them all into one:

if (circumferance > 0.0) {
  float radius = circumferance/(2 * pi);
  printf("Circumferance = %f, radius = %f\n", circumferance, radius)
}

In the preceding, the curly braces turn the two statements into one.

Like C, Scheme expects exactly one statement to be executed if the condition is true, so once again compound statements must be used. In this case, you make a compound statement using the begin operator:

(if (> circumferance 0)
   (begin
      (define radius (/ circumferance (* 2 pi)))
      (display "Circumferance = ")
      (display circumferance)
      (display ", radius = ")
      (display radius)
      (newline)
   )
)

The start operator takes an indefinite number of arguments, each of which must be a statement. When you need to make several statements look like one, use the begin operator.

Null Statements

Once again with if statements, occasionally you must have a null statement. Perhaps if something's true you want nothing done, but if it's false you want something done.

Of course, you can leave out the "if true" statement, because if you did then the intended "if false" statement would execute only when the condition was true, the exact opposite of what you want.

Obviously, the best fix is to refactor the if statement to switch true and false. That's what the not operator is for. But sometimes it isn't practical, so you need a null statement.

The following looks nice at first, but it doesn't work:

(define number 3)
   (if (> number 0)
     ()
     (display "The number is negative.")
)

The preceding gives you an "ERROR: Illegal empty combination ()." error. Instead, just use "true", which in Scheme is #t, as the true part of the if statement:

(define number 3)
(if (> number 0)
   #t
   (display "The number is negative.")
)

You could also use an empty begin statement, like this:

(define number 3)
(if (> number 0)
   (begin )
   (display "The number is negative.")
)

The best null statement is #t or #f, depending on the situation.

Subroutines

Subroutines, also called functions, procedures, operators, and who knows what else depending on language, are implemented by the lambda operator in Scheme. The reason it's defined with the lambda operator has to do with "lambda calculus", which is WAY beyond the scope of this document.

A Scheme subroutine looks like this:

(define subroutine_name
   (lambda (arg1 arg2 arg3)
      ; Subroutine code goes here
      ; Last statement executed defines return value
   ) ; end of lambda statement
) ; end of define statement

There's no return statement in Scheme. The last statement executed defines the return value:

(define add2
   (lambda (number1 number2)
      (+ number1 number2)
   ) ; end of lambda statement
) ; end of define statement

The preceding add2 function returns 10 if its args are 3 and 7, or 4 if its args are -3 and 7.

The following code includes a subroutine to calculate a hypotinuse, given the lengths of the two sides adjacent to the right angle of the triangle:

#!/usr/bin/guile
!#

(define hypotinuse
   (lambda(a b)
      (sqrt (+(* a a) (* b b)))
   )
)

(display (hypotinuse 1 1))
(newline)
(display (hypotinuse 3 4))
(newline)

In the preceding, the hypotinuse function returns the square root of the sum of the squares, as shown by the following output:

[slitt@mydesk scheme_guile]$ ./test.scm
1.4142135623731
5.0
[slitt@mydesk scheme_guile]$

The first display is the square root of two, which is obvious. The second is five, and we all know about three four five right triangles.

Functions Calling Other Functions

The preceding code has several examples of functions calling functions. For instance, the display function has one argument. In this case we chose that argument to be (hypotinuse 1 1). The display function called the hypotinuse function and used its function return.

Consider this code in the hypotinuse function:

(sqrt (+(* a a) (* b b)))

To make it clearer, let's break it out on separate lines and insert comments:

(sqrt                    ; square root. Of what? Of a2 + b2
   (+                    ; sum. Of what? a2 and b2
      (* a a)            ; a2
      (* b b)            ; b2
   )                     ; end of +
)                        ; end of sqrt

So sqrt calls +, which in turn calls * twice, once for a and once for b.

Recursion

When a function calls itself, that's called recursion. All modern computer languages are capable of recursion. Scheme expects recursion to be used often, so it's easy to do and easy to optimize.

To begin discussing recursion, take the two ways of describing factorial. The iterative way to describe it is "multiply the number by one less, and then that by one less, all the way down to one. The recursive way to describe it is "The factorial of a number is that number times the factorial of one less, unless the number is one, in which case the factorial is one." Let's code the recursive way first:

#!/usr/bin/guile
!#

(define fact_r
  (lambda (number)
    (if (= number 1)
      1
      (* number  (fact_r (- number 1)))
    )
  )
)

(display (fact_r 4))
(newline)

Return either 1 or fact_r of fact_r minus one. Nothing could be simpler.

Run it and it produces 24, just what you'd expect. Change the 4 to 4000 and it stack overflows. Ouch!

What happened is, each time it returns from fact_r, it does more work (multiplying the return from fact_r by the current number). That means all the way down, it must stack all variables, all state. The stack grows and eventually overflows.

Tail Recursion

You can save the stack with tail recursion. Tail recursion is recursion in which absolutely nothing is done with the return value except returning that return value to the caller. Because no state is being kept by each invocation of fact_r, Scheme can make optimizations to make the subroutine calls and returns more like gotos, eliminating most use of the stack. Let's rewrite the function so it does nothing with the return value except pass it on. In other words, tail recursive:

#!/usr/bin/guile
!#

(define fact_r
  (lambda (number)
    (if (= number 1)
      1
      (* number  (fact_r (- number 1)))
    )
  )
)

(define fact_tr
  (lambda (number accumulator)
    (if (= number 1)
      accumulator
      (fact_tr (- number 1) (* accumulator number))
    )
  )
)

(display (fact_tr 4 1))
(newline)

In the preceding, tail recursive fact_tr is substituted for fact_r. When fact_tr calls itself, it does nothing upon return but pass the return from called to caller.

Now that you're multiplying on the way in rather than on the way out, you need a way of passing the factorial into the called routine. That's done with the additional argument accumulator. Accumulator starts its life as 1 in the initial call.

Although this is technically a recursive use of the function, the actual algorithm is much more iterative than recursive. Its pseudocode looks like this:

number = 4
accumulator = 1
label topp:
   accumulator = accumulator * number
   number = number - 1
   if number > 1
      goto topp

print "The factorial is ", accumulator

Recursive designs are typically clean and tight, at least from the human viewpoint. The same cannot be said for subroutines refactored to take advantage of Scheme optimizations for tail recursion. Variables such as the accumulator variable must be added for no reason but to retain state, and gum up the works. It's not bad for a simple routine like factorial, but if you're programming something like a complex puzzle, all those state variables can really erect a barrier to scalability.

Anonymous Subroutines and "Pointers" to Subroutines

You haven't begun to harness the full power of the C programming language until you learn how to use pointers to functions. Pointers to functions enable "callback functions", which in turn make for code reusability meeting or exceding that of OOP languages.

For instance, a single sort routine can be used to sort strings, integers, string representations of integers, or even objects representing polar coordinate locations, just by changing the comparison function passed as an argument to the sort function.

Different data structures can have different functions to do similar actions. For instance, perhaps a data structure called "point" and another one called "circle" each have a function called "paint_yourself". If the "paint_yourself" function is a reference (pointer) to a function, this can be accomplished, even in a non-oop language, simply by assigning the correct function to the reference.

The following is the simplest implementation of function references in Scheme:

#!/usr/bin/guile
!#

(define a
  (lambda (arg)
    (display "Argument to function a is: ")
    (display arg)
    (newline)
  )
)

(define b
  (lambda (arg)
    (display "Argument to function b is: ")
    (display arg)
    (newline)
  )
)


(define caller
  (lambda (arg proc)
    (display "==== BEGIN CALLER ====\n")
    (proc arg)
    (display "====  END  CALLER ====\n\n")
  )
)

(caller "Test" a)
(caller "Test" b)

In the preceding, you passed a reference to the function itself, instead of the function return, by passing the name of the function. The preceding code produces the following output:

[slitt@mydesk scheme_guile]$ ./junk.scm
==== BEGIN CALLER ====
Argument to function a is: Test
====  END  CALLER ====

==== BEGIN CALLER ====
Argument to function b is: Test
====  END  CALLER ====

[slitt@mydesk scheme_guile]$

You can see that the argument itself is the same for both, but because the passed function references were different, in the output the prompt leading to the display of the argument is different (one says a and one says b). This example isn't very useful, but consider what can be done with two dimensional simple shapes:

#!/usr/bin/guile
!#

(define show_rectangle
  (lambda (x y width height)
    (display "Rectangle:\n")

    (display "Lower left  corner (x, y): (")
    (display (- x (/ width 2)))
    (display ", ")
    (display (- y (/ height 2)))
    (display ")\n")

    (display "Upper left  corner (x, y): (")
    (display (- x (/ width 2)))
    (display ", ")
    (display (+ y (/ height 2)))
    (display ")\n")

    (display "Upper right corner (x, y): (")
    (display (+ x (/ width 2)))
    (display ", ")
    (display (+ y (/ height 2)))
    (display ")\n")

    (display "Lower right corner (x, y): (")
    (display (+ x (/ width 2)))
    (display ", ")
    (display (- y (/ height 2)))
    (display ")\n")
  )
)

(define show_ellipse
  (lambda (x y width height)
    (display "Ellipse\n")
    (display "Center is (x, y): (")
    (display x)
    (display ", ")
    (display y)
    (display ")\n")
    (display "Horizongal radius is ")
    (display width)
    (display "\nVertical  radius is ")
    (display height)
    (newline)
  )
)

(define show_shape
  (lambda (proc x y width height)
    (display "==== BEGIN SHOWSHAPE ====\n")
    (proc x y width height)
    (display "====  END  SHOWSHAPE ====\n\n")
  )
)

(show_shape   show_rectangle    4   2   8   6)
(show_shape   show_ellipse      4   2   8   6)

The preceding code outputs the following:

[slitt@mydesk scheme_guile]$ ./shapes.scm
==== BEGIN SHOWSHAPE ====
Rectangle:
Lower left  corner (x, y): (0, -1)
Upper left  corner (x, y): (0, 5)
Upper right corner (x, y): (8, 5)
Lower right corner (x, y): (8, -1)
====  END  SHOWSHAPE ====

==== BEGIN SHOWSHAPE ====
Ellipse
Center is (x, y): (4, 2)
Horizongal radius is 8
Vertical  radius is 6
====  END  SHOWSHAPE ====

[slitt@mydesk scheme_guile]$

In Scheme, functions are just another kind of value, so you can pass them all over the place, store them in arrays and hashes, and pretty much have your way with them. It would be a kludge, but I bet you could simulate an OOP language, with Scheme, using function references.

Other Subroutine Examples

This section shows off and discusses some other subroutines.

#!/usr/bin/guile
!#

(define squared
	(lambda (x)
	(* x x)
	)
)

(display (squared 1))
(newline)
(display (squared 2))
(newline)
(display (squared 3))
(newline)
(display (squared 4))
(newline)

As expected, the preceding code yields the following output:

[slitt@mydesk scheme_guile]$ ./hello.scheme
1
4
9
16
[slitt@mydesk scheme_guile]$

The lambda function produces an unnamed procedure, and the define statement assigns that unnamed procedure to variable squared.

The following procedure, showme, prints its argument and then a newline:

#!/usr/bin/guile
!#

(define showme
	(lambda (x)
		(display x) 
		(newline)
	)
)

(showme 1)
(showme 2)
(showme "Steve was here.")

The preceding code produces the following output:

[slitt@mydesk scheme_guile]$ ./hello.scheme
1
2
Steve was here.
[slitt@mydesk scheme_guile]$

Notice that the showme procedure works with either numbers or strings. The following shows a procedure with two arguments, height and width, that returns the area of a rectangle:

#!/usr/bin/guile
!#

(define showme
	(lambda (x)
	(display x) 
	(newline)
	)
)

(define area
	(lambda (height width)
	(* height width)
	)
)
	

(showme (area 5 3))
(showme (area 4 4))
(showme (area 3 5))

The preceding produces the expected result as follows:

[slitt@mydesk scheme_guile]$ ./hello.scheme
15
16
15
[slitt@mydesk scheme_guile]$

Set!

When a variable has been declared with define, it can be changed with set!. Note the exclamation point at the end -- that's imperitive. In general, operators ending in exclamation points change their operand in place, whereas operators without exclamation points, if they change the operand at all, change a copy of it which can then be passed back via the function return.

#!/usr/bin/guile
!#
(define hi "Hello World")
(display hi)
(newline)
(set! hi "Goodbye")
(display hi)
(newline)

Local Variables

By default, Scheme variables are global. You have to go to great lengths to create and use local variables. Local variables are created with the let, let* and letrec operators. The variables are local only within the the let, let* or letrec statement. The letrec operator will not be discussed here.

The syntax of both let and let* looks like this:

(let (<binding list>) <body>)

Check out the following code example, and its output:

#!/usr/bin/guile
!#

(define x 20)
(display x) (newline)

(let ((x 5))
  (display x) (newline)
  (set! x 7)
  (display x) (newline)
)

(display x) (newline)
[slitt@mydesk scheme_guile]$ ./test.scm
20
5
7
20
[slitt@mydesk scheme_guile]$

Variable x is set globally to 20, and then set to 5 locally to the let statment. In the let statement body it's set to 7. After the end of the let statement, x returns to its pre-let value of 20. A few other observations:

The following demonstrates the workings of let and let*:, with let* being run with the local variable bindings in both orders:

#!/usr/bin/guile
!#

(define x 20)
(display x) (newline)

(let ((x 5) (y (* x 4)))
  (display x) (newline)
  (set! x (+ x y))
  (display x) (newline)
)

(display x) (newline)

(display "=====================\n")

(define x 20)
(display x) (newline)

(let* ((x 5) (y (* x 4)))
  (display x) (newline)
  (set! x (+ x y))
  (display x) (newline)
)

(display x) (newline)

(display "=====================\n")

(define x 20)
(display x) (newline)

(let* ((y (* x 4)) (x 5))
  (display x) (newline)
  (set! x (+ x y))
  (display x) (newline)
)

(display x) (newline)
[slitt@mydesk scheme_guile]$ ./test.scm
20
5
85
20
=====================
20
5
25
20
=====================
20
5
85
20
[slitt@mydesk scheme_guile]$

On all three runs, the first, second and fourth displays of x are equal. However, the third display of x is 85 in the first and third run, but only 25 in the middle run. Here's why:

With let, binding doesn't take effect until after the binding list, meaning that when y is set to four times x, the old value of x is still in effect, so y is 80.

However, with let*, the bindings are done in the same order as listed in the bindings list, and take effect immediately. In the middle run, x is bound to 5 before y is bound to four times x, so y is 20 instead of 80 because the new value of x has already taken effect.

The third run has the same effect as the first, because although you're still using let*, x hasn't yet been bound when y is bound to four times x, so once again the global value of x is used.

If for some reason your binding list has some locals depending on others, carefully select whether you want let or let*, and if you use let* be very careful about binding order if you use let*. If you absolutely have to bind a local variable based on another local variable (as in the middle run of the preceding exercise), adding one more statement can make everything crystal clear even to a novice maintenance programmer:

#!/usr/bin/guile
!#


(define x 20)
(display x) (newline)

(let* ((x 5) (y "dummyvalue"))
  (set! y (* x 4))
  (display x) (newline)
  (set! x (+ x y))
  (display x) (newline)
)

(display x) (newline)
[slitt@mydesk scheme_guile]$ ./test.scm
20
5
25
20
[slitt@mydesk scheme_guile]$

Global variables are a very bad idea with all but the smallest programs, or in situations where one variable is used absolutely everywhere, usually as a constant. The culturally correct way to avoid globals in Scheme is not to declare variables at all, but to simply use a subroutine's arguments as the only variables. If you have to declare variables, especially within a subroutine, its best to make them local by having a let or let* statement immediately inside the lambda statement, and having all the logic inside the let section. This might, however, mess with tail recursion optimization, so you'll have to check that in cases where you're using tail recursion to save stack.

Tail Recursion Pros and Cons

As mentioned earlier, tail recursion is useful to reduce stack usage because Scheme implements it more like a goto, but tail recursion usually waters down recursive design and requires several context or accumulator variables. Regular recursion is usually a much simpler design. To explore this tradeoff, let's discuss the Comp Sci 101 recursion program, the Fibonacci Numbers.

Recursive Fibonacci generation is tougher on stack and CPU because each instantiation calls two different instantiations of itself, so instead of simply descending, it forms an inverse tree whose leaves number almost 2n:

fibb(10)-----fibb(9)-----fibb(8)-----fibb(7)-----fibb(6)
          |           |           |           `--fibb(5)
          |           |           |
          |           |           `--fibb(6)-----fibb(5)
          |           |                       `--fibb(4)
          |           |
          |           `--fibb(7)-----fibb(6)-----fibb(5)
          |                       |           `--fibb(4)
          |                       |
          |                       `--fibb(5)-----fibb(4)
          |                                   `--fibb(3)
          |
          `--fibb(8)-----fibb(7)-----fibb(6)-----fibb(5)
                      |           |           `--fibb(3)
                      |           |           
                      |           `--fibb(5)-----fibb(4)
                      |                       `--fibb(3)
                      |
                      `--fibb(6)-----fibb(5)-----fibb(4)
                                  |           `--fibb(3)
                                  |
                                  `--fibb(4)-----fibb(3)
                                              `--fibb(2)

This is much more than geometric growth, so that to calculate the 30th Fibonacci number, the recursive design would require somewhere in the neighborhood of 230  (1,073,741,824) calculations, whereas an iterative design would require 30 calculations. Clearly this requires an iterative design taking advantage of tail recursion, even though the code is much less intuitive. The following code and its subsequent output demonstrate both a design recursive and tail recursive algorithm and their timings:

#!/usr/bin/guile
!#

(define fibb
  (lambda (num)
    (if (> num 2)
      (+ (fibb (- num 1)) (fibb (- num 2)))
      1
    )
  )
)

(define fibb_tr
  (lambda (limit accum accumlast)
    (if (> limit 1)
      (fibb_tr (- limit 1) (+ accum accumlast) accum)
      accum
    )
  )
)

(define x 1)
(while (< x  10)
   (display (fibb x))
   (display "  :::  ")
   (display (fibb_tr x 1 0))
   (newline)
   (set! x (+ x 1))
)


(define bigfibb 38)
(define timea (current-time))
(display (fibb_tr bigfibb 1 0))
(newline)
(display "==================\n")
(define timeb (current-time))
(display (fibb bigfibb))
(newline)
(define timec (current-time))
(display "\n\nTail recursive version took ")
(display (- timeb timea))
(display " seconds.\n")
(display "\n\nReal recursive version took ")
(display (- timec timeb))
(display " seconds.\n")
[slitt@mydesk scheme_guile]$ ./test.scm 
1  :::  1
1  :::  1
2  :::  2
3  :::  3
5  :::  5
8  :::  8
13  :::  13
21  :::  21
34  :::  34
39088169
==================
39088169


Tail recursive version took 0 seconds.


Real recursive version took 25 seconds.
[slitt@mydesk scheme_guile]$

In the preceding code, the fibb code is much more intuitive, and uses less arguments, than the fibb_tr code. Both come up with the same numbers. But when it comes to timing, the tail recursive technique took much less than a second for the 38th Fibonacci number, while the design-recursive method took 25 seconds to do the same thing.

Of course, Fibonacci is unusual in that each invocation calls two. But not that unusual. Many puzzles require multiple recursive calls per invocation. A backtracking algorithm to run a maze requires each invocation to call itself up to four times -- one for north, one for east, one for south and one for west.  Same with a recursive program to solve a chicklet puzzle (15 numbered chicklets in a 4x4 frame, so you need to push chicklets around in order to sort the chicklets). I can't even imagine the recursive spread on a chess playing program. Recursive programs with recursive spread can quickly swamp the CPU.

But even recursive designs that call themselves only once can deplete the stack. Scheme's tail recursion optimizations mean each invocation stores much less on the stack, and you can run a much higher count with tail recursion than with the corresponding design recursion.

My advice -- try it first with a true recursive design, and see how well it works, at least for small test cases. Once you have it right, if it's too slow you can  convert it to tail recursion, passing accumulators and upper limits to the recursive subroutine.

True or False (#t or #f)

True is represented by #t. False by #f.  These can be used in if statements (discussed later on).

#!/usr/bin/guile
!#
(display (< 1 2))
(newline)
(display (= 1 2))
(newline)
(display (> 1 2))
(newline)

In the preceding code, the first one is true because 1 is less than 2. The second is false because 1 is not equal to 2, and the third statement is false because 1 is not more than 2. As expected, the preceding code produces the following output:

[slitt@mydesk scheme_guile]$ ./hello.scheme
#t
#f
#f
[slitt@mydesk scheme_guile]$

Relational Operators

Check out the following code and subsequent output:

#!/usr/bin/guile
!#
(display "========== NUMERIC <, =, >, <=, = AND >= =========")
(newline)
(display (< 1 2))
(newline)
(display (= 1 2))
(newline)
(display (> 1 2))
(newline)
(display (<= 1 2))
(newline)
(display (= 1 2))
(newline)
(display (>= 1 2))
(newline)
(display "========== NUMERIC <, =, >, <=, = AND >= on equal numbers =========")
(newline)
(display (< 1 1))
(newline)
(display (= 1 1))
(newline)
(display (> 1 1))
(newline)
(display (<= 1 1))
(newline)
(display (>= 1 1))
(newline)
(display "========== STRING <, =, >, <=, = AND >= ON EQUAL STRINGS =========")
(newline)
(newline)
(display (string<? "scheme" "scheme"))
(newline)
(display (string=? "scheme" "scheme"))
(newline)
(display (string>? "scheme" "scheme"))
(newline)
(display (string<=? "scheme" "scheme"))
(newline)
(display (string=? "scheme" "scheme"))
(newline)
(display (string>=? "scheme" "scheme"))
(newline)
(display "========== STRING <, =, >, <=, = AND >= ON unEQUAL STRINGS =========")
(newline)
(display (string<? "scheme" "steve"))
(newline)
(display (string=? "scheme" "steve"))
(newline)
(display (string>? "scheme" "steve"))
(newline)
(display (string<=? "scheme" "steve"))
(newline)
(display (string=? "scheme" "steve"))
(newline)
(display (string>=? "scheme" "steve"))
(newline)

The preceding code produces the following output, as expected:

========== NUMERIC <, =, >, <=, = AND >= =========
#t
#f
#f
#t
#f
#f
========== NUMERIC <, =, >, <=, = AND >= on equal numbers =========
#f
#t
#f
#t
#t
========== STRING <, =, >, <=, = AND >= ON EQUAL STRINGS =========

#f
#t
#f
#t
#t
#t
========== STRING <, =, >, <=, = AND >= ON unEQUAL STRINGS =========
#t
#f
#f
#t
#f
#f
[slitt@mydesk scheme_guile]$ 

Compound Conditions

#!/usr/bin/guile
!#
(display (and (< 5 10) (> 5 1)))
(newline)
(display (or (< 5 5) (> 5 5)))
(newline)

The preceding code produces the following output:

[slitt@mydesk scheme_guile]$ ./hello.scheme
#t
#f
[slitt@mydesk scheme_guile]$

If Statements

If statements are quite different in Scheme than in C, Perl, Java and the like. Here is the basic syntax of a Scheme if statement:

(if condition
   execute_if_true
   execute_if_false
)

The condition will probably be a relational statement in parentheses. The execute_if_true and execute_iif_false will also likely be in parentheses. Here's an example:

#!/usr/bin/guile
!#

(define over5?
   (lambda (x)
      (if (> x 5)
         (display "x is more than 5\n")
         (display "x is NOT more than 5\n")
      )
   )
)

(define countdown
   (lambda (x)
      (display "Iteration ")
      (display x)
      (display ", ")
      (over5? x)
      (if (> x 0)
         (countdown (- x 1))
      )
   )
)

(countdown 10)

Look at the if statement in function over5?. The first statement is what's done if it's true, the second statement is what's done if it's false. Here's the result of the preceding code:

[slitt@mydesk scheme_guile]$ ./hello.scheme
x is 10, x is more than 5
x is 9, x is more than 5
x is 8, x is more than 5
x is 7, x is more than 5
x is 6, x is more than 5
x is 5, x is NOT more than 5
x is 4, x is NOT more than 5
x is 3, x is NOT more than 5
x is 2, x is NOT more than 5
x is 1, x is NOT more than 5
x is 0, x is NOT more than 5
[slitt@mydesk scheme_guile]$

Note that the first STATEMENT is executed when true and the second STATEMENT is executed when false. It has nothing to do with lines. You could put both statements on the same line and the results would be the same:

#!/usr/bin/guile
!#

(define over5?
   (lambda (x)
      (if (> x 5)
         (display "x is more than 5\n") (display "x is NOT more than 5\n")
      )
   )
)

(define countdown
   (lambda (x)
      (display "x is ")
      (display x)
      (display ", ")
      (over5? x)
      (if (> x 0)
         (countdown (- x 1))
      )
   )
)

(countdown 10)

So what do you do if you really need to execute several statements when it's true, or when it's false. For instance, what if in the preceding code we want to use (newline) instead of including a \n in the string:

#!/usr/bin/guile
!#

(define over5?
   (lambda (x)
      (if (> x 5)
         (display "x is more than 5") (newline)
         (display "x is NOT more than 5") (newline)
      )
   )
)

(define countdown
   (lambda (x)
      (display "x is ")
      (display x)
      (display ", ")
      (over5? x)
      (if (> x 0)
         (countdown (- x 1))
      )
   )
)

(countdown 10)

Here's the resultt:

[slitt@mydesk scheme_guile]$ ./hello.scheme
x is 10, ERROR: In procedure memoization:
ERROR: Missing or extra expression in (if (> x 5) (display "x is more than 5") (newline) (display "x is NOT more than 5") (newline)).
[slitt@mydesk scheme_guile]$

That's pretty ugly. What you need is a way to make several statements appear like one statement. That's the purpose of the begin function or operator or whatever you call it. You wrap all the statements you want to appear as one in (begin ), so it looks something like this:

(begin
	statement1
	statement2
	statement3
)

Here's what the program containing the over5? procedure looks like using begin:

#!/usr/bin/guile
!#

(define over5?
   (lambda (x)
      (if (> x 5)
         (begin (display "x is more than 5") (newline))
         (begin (display "x is NOT more than 5") (newline))
      )
   )
)

(define countdown
   (lambda (x)
      (display "x is ")
      (display x)
      (display ", ")
      (over5? x)
      (if (> x 0)
         (countdown (- x 1))
      )
   )
)

(countdown 10)

Will it work? Here is the output:

[slitt@mydesk scheme_guile]$ ./hello.scheme
x is 10, x is more than 5
x is 9, x is more than 5
x is 8, x is more than 5
x is 7, x is more than 5
x is 6, x is more than 5
x is 5, x is NOT more than 5
x is 4, x is NOT more than 5
x is 3, x is NOT more than 5
x is 2, x is NOT more than 5
x is 1, x is NOT more than 5
x is 0, x is NOT more than 5
[slitt@mydesk scheme_guile]$

It worked! Note that it would have worked just as well if the contained statements were on different lines and the closing paren for the begin were below the last contained statement. The (begin statement statement) technique is very much like compound statements in C, Perl, Pascal, Java and the like.

Using cond to Implement Else If Statements

The if statements in the preceding section are excellent for simple logic, but if you have a bunch of "else if" logic, each "else if" would be increasingly buried in the logic, as follows:

#!/usr/bin/guile
!#

(define digits
   (lambda (n)
      (if (< n 10)
         1
         (if (< n 100)
            2
            (if (< n 1000) 
               3
               "More than three digits"
            )
         )
      )
   )
)

(define countdown
   (lambda (x)
      (display "x is ")
      (display x)
      (display ", ")
      (display (digits x))
      (newline)
      (if (>= x 1)
         (countdown (/ x 2))
      )
   )
)

(countdown 1024)

Whooo doggies, that's some nasty code! Look at the digits function -- the elsifs march right across the page. The preceding ugly code produces the following, expected results:

[slitt@mydesk scheme_guile]$ ./junk.scm
x is 1024, More than three digits
x is 512, 3
x is 256, 3
x is 128, 3
x is 64, 2
x is 32, 2
x is 16, 2
x is 8, 1
x is 4, 1
x is 2, 1
x is 1, 1
x is 1/2, 1
[slitt@mydesk scheme_guile]$

For neater code that implements real elsifs, try cond.

#!/usr/bin/guile
!#

(define digits
   (lambda (n)
      (cond ((< n 10) 1)
      ((< n 100) 2)
      ((< n 1000) 3)
      (else "More than three digits")
      )
   )
)

(define countdown
   (lambda (x)
      (display "x is ")
      (display x)
      (display ", ")
      (display (digits x))
      (newline)
      (if (>= x 1)
         (countdown (/ x 2))
      )
   )
)

(countdown 1024)

Note that in some Scheme implementations, you can use square brackets to surround each condition and result, but that doesn't work in Guile. The preceding code does what you'd expect:

[slitt@mydesk scheme_guile]$ ./hello.scheme 
x is 1024, More than three digits
x is 512, 3
x is 256, 3
x is 128, 3
x is 64, 2
x is 32, 2
x is 16, 2
x is 8, 1
x is 4, 1
x is 2, 1
x is 1, 1
x is 1/2, 1
[slitt@mydesk scheme_guile]$

The output is the same as that of the ugly code.

Loops

The built-in, simple way to loop in Scheme is through recursion:

#!/usr/bin/guile
!#

(define printit
   (lambda (x)
      (display "This is iteration ")
      (display x)
      (newline)
      (if (> x 0)
         (printit (- x 1))
      )
   )
)

(printit 10)

The preceding code prints the following, which may not be what you wanted:

[slitt@mydesk scheme_guile]$ ./hello.scheme
This is iteration 10
This is iteration 9
This is iteration 8
This is iteration 7
This is iteration 6
This is iteration 5
This is iteration 4
This is iteration 3
This is iteration 2
This is iteration 1
This is iteration 0
[slitt@mydesk scheme_guile]$

The preceding counted down from 10 through 0. It did this because, if you look carefully at the code, you see that the printing takes place AFTER the function call returned, not before. So the deepest call prints first. You may have wanted to count from 0 up through 10. One way to do that is the following:

#!/usr/bin/guile
!#

(define printit
   (lambda (x)
      (if (> x 0)
         (printit (- x 1))
      )
      (display "This is iteration ")
      (display x)
      (newline)
   )
)

(printit 10)

Here's the output:

[slitt@mydesk scheme_guile]$ ./hello.scheme
This is iteration 0
This is iteration 1
This is iteration 2
This is iteration 3
This is iteration 4
This is iteration 5
This is iteration 6
This is iteration 7
This is iteration 8
This is iteration 9
This is iteration 10
[slitt@mydesk scheme_guile]$

Just what you wanted! The preceding  would be perfect except for one thing: It's not tail-recursive. Tail recursive means that the call to itself occurs as the final computation of the function. With a properly optimized language such as Scheme, a tail-recursive function is optimized so the function's state isn't kept on the stack -- it's not needed because upon return from the called invocation of the function, the caller has nothing further to do. So Scheme treats tail recursion more like goto, which may be ugly software engineering, but it's machine-efficient.

The following is a tail-recursive way to do the same thing:

#!/usr/bin/guile
!#

(define printit
   (lambda (x org_x)
      (display "This is iteration ")
      (display (- org_x x))
      (newline)
      (if (> x 0)
         (printit (- x 1) org_x)
      )
   )
)

(printit 10 10)

The preceding code produces the following output:

[slitt@mydesk scheme_guile]$ ./hello.scheme
This is iteration 0
This is iteration 1
This is iteration 2
This is iteration 3
This is iteration 4
This is iteration 5
This is iteration 6
This is iteration 7
This is iteration 8
This is iteration 9
This is iteration 10
[slitt@mydesk scheme_guile]$

Here you passed two arguments. The first varied from call to call, while the second was preserved, and served to indicate the original value. The good news is, the function's call to itself was the very last action taken -- it's tail recursive.

Some Gotchas

The following program is subtly wrong, and the problem produces the dreaded and hard to solve "Wrong type to apply" error.

#!/usr/bin/guile
!#

(define iterate
   (lambda(x x_org)
      (display "x is ")
      (display (- x_org x))
      (newline)
      (if (> x 0)
         (iterate ((- x 1) x_org))
      )
   )
)

(iterate 10 10)

The preceding code unexpectedly produces the following:

[slitt@mydesk scheme_guile]$ ./hello.scheme 
x is 0
ERROR: Wrong type to apply: 9
[slitt@mydesk scheme_guile]$

The problem is caused by an extra pair of parentheses in the recursive call. The recursive call is shown below, with the extra parentheses in large red:

(iterate ((- x 1) x_org))

It's natural for anyone familiar with C, Perl, Java and the like to forget they're in Scheme and instead do what they'd do in C, put the arguments to the function in a set of parentheses. If you do that in Scheme you get the dreaded "Wrong type to apply" error. If you remove the offending parenthese, it counts up from 0 to 10, just the way you want it to.

Another way to get the "Wrong type to apply" error is to add parentheses around the x_org argument:

(iterate (- x 1) (x_org))

When quickly typing in code, it might seem symetrical to put both args in parentheses, but that would be wrong and produce the dreaded error.

Whenever you see the "Wrong type to apply" error, look at the argument that the error message says is wrong, try to find where that value would exist, and in that area look for an extra pair of parentheses.

See if you can see what's wrong with the following:

#!/usr/bin/guile
!#

(define iterate
   (lambda(x x_org)
      (display "x is ")
      (display (- x_org x)
      (newline)
      (if (> x 0)
         (iterate (- x 1) x_org)
      )
   )
)

(iterate 10 10)

The preceding code produces the following error message:

[slitt@mydesk scheme_guile]$ ./hello.scheme 
ERROR: In procedure scm_i_lreadparen:
ERROR: ./hello.scheme:16:1: end of file
[slitt@mydesk scheme_guile]$

Line 16 is one line past the last line in the program, so it isn't handy for locating the problem. The scm_i_lreadparen points an accusing finger at parenthese, and combined with the fact that it discusses the end of file, it's a good indication that the problem is one too few right parentheses, or one too many left ones. In this case, the problem is here:

(display (- x_org x)

There's no closing paren.

These are very hard to find. The best way I know of is to use the process of elimination. If the problem is in a specific function, you can kill the error message by not calling the offending function. So in simpler programs you can comment out function calls to identify the offending function. Once you have it down to a function, you can comment out chunks of code until the problem goes away to identify it down to one or a few lines of code.

Real Loops

Looping with recursion is kind of cute, but in real algorithms with lots of state and data, recursive looping is confusing for the programmer and inefficient for the computer.

Several iterative loops have been made. The ones most built into the language are the while loop, the do-loop,  and map loops. While loops are simple and give the opportunity to use break and continue. Do loops are more complex and powerful, with a place for everything, but they're hard to understand. Map loops are made to iterate through lists.

While Loops

While loops are simple and very general. They're roughly analogous to while loops in C.

#!/usr/bin/guile
!#

(define x 0)
(while (<= x 10)
   (display "x is ")
   (display x)
   (newline)
   (set! x (+ x 1))
)

Simple, isn't it. The result follows:

[slitt@mydesk scheme_guile]$ ./hello.scheme 
x is 0
x is 1
x is 2
x is 3
x is 4
x is 5
x is 6
x is 7
x is 8
x is 9
x is 10
[slitt@mydesk scheme_guile]$

You can also use a "forever loop" with a break statement:

#!/usr/bin/guile
!#

(define x 0)
(while 
   (if (> x 10)
      (break)
   )
   (display "x is ")
   (display x)
   (newline)
   (set! x (+ x 1))
)

The preceding code produces the same output:

[slitt@mydesk scheme_guile]$ ./hello.scheme 
x is 0
x is 1
x is 2
x is 3
x is 4
x is 5
x is 6
x is 7
x is 8
x is 9
x is 10
[slitt@mydesk scheme_guile]$

The following, contrived while loop has both a break and a continue statement:

#!/usr/bin/guile
!#

(define x -1)
(while 
   (set! x (+ x 1))
   (if (> x 100)
      (break)
   )

   (display ".")
   (if (< x 90)
      (continue)
   )

   (display "x is ")
   (display x)
   (newline)
)

If the code works as expected, it should print nothing but a dot until x is 90, and from 90 to 100 it should print the whole sentence.  The loop terminates at 101.

[slitt@mydesk scheme_guile]$ ./hello.scheme 
...........................................................................................x is 90
.x is 91
.x is 92
.x is 93
.x is 94
.x is 95
.x is 96
.x is 97
.x is 98
.x is 99
.x is 100
[slitt@mydesk scheme_guile]$

While loops are simple, clean and pose no surprise for C, Perl and Java programmers.

Do Loops

Do Loops are probably even more confusing than recursion, but they're very powerful. They're roughly analogous to For loops in C. Here's perhaps the simplest implementation:

#!/usr/bin/guile
!#

(do
   ((x 1 (+ x 1)))
   ((> x 5) (display "Loop finished.\n"))
   (display "x is ")
   (display x)
   (newline)
)

Repeat after me: Uuuuugly!

The recursive version was much cleaner. Let me try to shed some light...

The do construct takes an indefinite number of arguments.

  1. The do first argument is a set of statements, one per variable, that lists three things about the variable: 
    1. The variable name, 
    2. its starting value, and 
    3. its incrementation statement (optional)
  2. The second do argument consists of two statements
    1. The test which, when true, terminates the loop
    2. Code to run after loop termination. This can actually be 0 to infinity statements
  3. Statements  comprising the body of the loop. If there's no incrementation statement in the first 

The preceding code outputs the following:

[slitt@mydesk scheme_guile]$ ./hello.scheme 
x is 1
x is 2
x is 3
x is 4
x is 5
Loop finished.
[slitt@mydesk scheme_guile]$

The following code works on two variables, x and y:

#!/usr/bin/guile
!#

(do
   ((x 1 (+ x 1)) (y 10 (- y 1))) ; variable names, start vals and increments
   ((> x 10) (display "Loop finished.\n")) ; Test criteria and post-break code
   (display "x is ") ; Body of loop starts here
   (display x)
   (display ", y is ")
   (display y)
   (display ", x+y is ")
   (display (+ x y))
   (newline)
)

Study the preceding carefully. It's not as convoluted as it first appears. Its output follows:

[slitt@mydesk scheme_guile]$ ./hello.scheme 
x is 1, y is 10, x+y is 11
x is 2, y is 9, x+y is 11
x is 3, y is 8, x+y is 11
x is 4, y is 7, x+y is 11
x is 5, y is 6, x+y is 11
x is 6, y is 5, x+y is 11
x is 7, y is 4, x+y is 11
x is 8, y is 3, x+y is 11
x is 9, y is 2, x+y is 11
x is 10, y is 1, x+y is 11
Loop finished.
[slitt@mydesk scheme_guile]$

Map Loops

Map loops iterate over a list (array). The following is an example:

#!/usr/bin/guile
!#

(define mylist '(1 3 5 7 9))
(map
   (lambda (x)
      (display "This mylist element is ")
      (display x)
      (newline)
   )
   mylist
)

The preceding produces the following output:

[slitt@mydesk scheme_guile]$ ./hello.scheme 
This mylist element is 1
This mylist element is 3
This mylist element is 5
This mylist element is 7
This mylist element is 9
[slitt@mydesk scheme_guile]$

Map works like this:

(map
	<subroutine to execute on each element>
	<list to iterate over>
)

Map, and a related procedure called for-each, can be used in many ways besides this. You can familiarize yourself with them as needed.

Scheme's Pretty Efficient

Check out these timings, keeping in mind they were run, in 2009, on a 2008 commodity computer. The following is the code used to do the timings. It first calculates the factorial of a number. It then checks the answer by dividing by incrementing divisors until the remainder is 1.

NOTE:

On 1/14/2025 I ran this same code, using 200000 as the number, on my 2020 AMD Ryzen 5 3600 6-Core with 64GB RAM. The program took 61.89 seconds, as opposed to the 150.21 seconds required by the 2008 hardware

#!/usr/bin/guile
!#

(define fact
  (lambda (x accum)
    (set! accum (* accum x))
    (if (< x 2)
      accum
      (fact (- x 1) accum)
    )
  )
)

(define defactorialize
  (lambda (accum times)
    (set! accum (/ accum times))
    (if (> accum 1)
      (defactorialize accum (+ times 1))
      (list accum times)
    )
  )
)

(define debugging #f)

(define fnumber 60)
(define factorial (fact fnumber 1))

(if (not debugging) (display factorial))

; FOLLOWING LINE TESTS ACCURACY AND PRECISION OF defactorialize
(if debugging (set! factorial (- factorial 1)))

(newline)
(display "About to defactorialize...\n")
(newline)
(define deflist (defactorialize factorial 1))

(display "Defactorialize divided the accumulator down to ")
(display (list-ref deflist 0))
(display ".\n")
(display "The number factorialized according to defactorialize is ")
(display (list-ref deflist 1))
(display ".\n")

The preceding calculates 60 factorial. That's an 82 digit number. It then checks the answer by dividing by incrementing divisors until the remainder is 1. Ellapsed time: a hundredth of a second.

[slitt@mydesk scheme_guile]$ time ./fact.scm
8320987112741390144276341183223364380754172606361245952449277696409600000000000000
About to defactorialize...

Defactorialize divided the accumulator down to 1.
The number factorialized according to defactorialize is 60.
0.01user 0.00system 0:00.01elapsed 90%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+575minor)pagefaults 0swaps
[slitt@mydesk scheme_guile]$

Let's try it for 100 factorial, 1000 factorial and 10,000, 100,000 and 200,000 factorial:

Number
to
factorialize
Ellapsed
time
(seconds)
600.01
1000.01
10000.01
100000.36
10000033.49
200000150.21

When reviewing these timings, keep in mind that 200,000 factorial has  973,352 digits. That's a huge number. The size of the universe is less than 1031 millimeters, less than 1072 Planck units. A Planck unit is the smallest distance or size about which anything can be known. It's 1/1020 the size of a proton. You could cube the number of Planck units in the diameter of the universe, and it would still be dwarfed by 200,000 factorial. That's right, the volume in the universe in Planck3 is dwarfed by 200,000 factorial. My 1 year old commodity computer can compute 200,000 factorial, using the Guile implementation of Scheme, in two and a half minutes!

Data in Scheme

Note:

This section isn't yet complete.

There are many types of data in Scheme. Here are a few:

Numbers

Numbers have been discussed pretty well in this document, although of course there are many more functions that can work on numbers. Research as needed.

Strings

The following code converts a string to an array, one character per element, and reads the the array with a map command:

#!/usr/bin/guile
!#

(define mylist '(1 2))
(define mystring "Steve was here.")
(set! mylist (string->list mystring))

(map
	(lambda (x)
	(display "This mylist element is ")
	(display x)
	(newline)
	)
	mylist
)

Not surprisingly, it produces the following:

[slitt@mydesk scheme_guile]$ ./hello.scheme
This mylist element is S
This mylist element is t
This mylist element is e
This mylist element is v
This mylist element is e
This mylist element is 
This mylist element is w
This mylist element is a
This mylist element is s
This mylist element is 
This mylist element is h
This mylist element is e
This mylist element is r
This mylist element is e
This mylist element is .
[slitt@mydesk scheme_guile]$

It's easier to handle it directly as a string though. Here are some handy string functions:

Lists

Scheme lists are a lot like arrays in other languages

#!/usr/bin/guile
!#

(define showthing
	(lambda (prompt thing)
		(display prompt)
		(display ": ")
		(display thing)
		(newline)
	)
)

(define showlist
	(lambda (listname listt)
		(define firstime 1)
		(display listname)
		(display "=(")
		(map
			(lambda (x)
				(if (= firstime 1)
					(set! firstime 0)
					(display " ")
				)
				(display x)
			)
			listt
		)
		(display ")")
		(newline)
	)
)

(define mylist (list "one" "two" "three" "four"))

(showlist "mylist top" mylist)
(showthing "car mylist" (car mylist))
(showlist "mylist after car" mylist)
(showthing "cdr mylist" (cdr mylist))
(showlist "mylist after cdr" mylist)
;(showlist "car mylist" (car mylist))

(define ss 0)
(while (< ss (length mylist))
	(showthing "  While loop: element"  (list-ref mylist ss))
	(set! ss (+ ss 1))
)
(showlist "mylist after while loop" mylist)
(append! mylist (list "five"))
(showlist "mylist after append! loop" mylist)
(set! mylist (cons "zero" mylist))
(showlist "mylist after set! cons loop" mylist)
(append! mylist (list "six" "seven" "eight") (list "nine" "ten"))
(showlist "mylist after append six thru ten" mylist)
(set! mylist (append (list "negone") mylist (list "eleven")))
(showlist "mylist after append before and after" mylist)

The preceding code produced the following output:

[slitt@mydesk scheme_guile]$ ./hello.scheme
mylist top=(one two three four)
car mylist: one
mylist after car=(one two three four)
cdr mylist: (two three four)
mylist after cdr=(one two three four)
  While loop: element: one
  While loop: element: two
  While loop: element: three
  While loop: element: four
mylist after while loop=(one two three four)
mylist after append! loop=(one two three four five)
mylist after set! cons loop=(zero one two three four five)
mylist after append six thru ten=(zero one two three four five six seven eight nine ten)
mylist after append before and after=(negone zero one two three four five six seven eight nine ten eleven)
[slitt@mydesk scheme_guile]$

x

Command Line Arguments

Here's a piece of code to showcase command line argument handling in Scheme:

#!/usr/bin/guile
!#


(display (command-line))
(newline)
(define argv (command-line))
(define argc (length argv))
(define argno 0)

(display "Argc is ")
(display argc)
(newline)
(while (< argno argc)
       (display "Arg ")
       (display argno)
       (display " is ")
       (display (list-ref argv argno))
       (newline)
       (set! argno (+ argno 1))
)

The preceding code produces the following output:

[slitt@mydesk scheme_guile]$ ./argv.scm one two three four five
(./argv.scm one two three four five)
Argc is 6
Arg 0 is ./argv.scm
Arg 1 is one
Arg 2 is two
Arg 3 is three
Arg 4 is four
Arg 5 is five
[slitt@mydesk scheme_guile]$

File I/O

Start by creating the following test.txt file:

Steve was here
and now is gone
but left his name
to carry on.

Now write the following program:

#!/usr/bin/guile
!#

(define inf (open-input-file "test.txt"))

(define mystring "initialization value")

(while #t
   (set! mystring (read inf))
   (if (eof-object? mystring)
      (break)
      (display mystring)
   )
   (newline)
)

The preceding program produces the following output:

[slitt@mydesk scheme_guile]$ ./readwrite.scm 
Steve
was
here
and
now
is
gone
but
left
his
name
to
carry
on.
[slitt@mydesk scheme_guile]$

That's nice. The program was nice enough to split words, but it lost the newlines. You can always find word boundaries, but once it throws away the newline, you can never get it back. The character-at-a-time read doesn't throw away the newline:

#!/usr/bin/guile
!#

(define inf (open-input-file "test.txt"))

(define mychar "initialization value")

(while #t
   (set! mychar (read-char inf))
   (if (eof-object? mychar)
      (break)
      (display mychar)
   )
)

The preceding code produced the following

[slitt@mydesk scheme_guile]$ ./readwrite.scm 
Steve was here
and now is gone
but left his name
to carry on.
[slitt@mydesk scheme_guile]$

The preceding code has all the disadvantages of character-at-a-time. I'd imagine it would be slow. But if necessary, it could be used to create a line at a time read, as exampled by the readline function in the following code:

#!/usr/bin/guile
!#

(define readline
   (lambda (infile)
      (define c "initialization")
      (define returnstring "")
      (while #t
         (set! c (read-char infile))
         (if (eof-object? c) (break))
         (if (char=? c #\newline) (break))
         (set! returnstring (string-append returnstring (string c)))
      )
      (if (eof-object? c)
         c
         returnstring
      )
   )
)

(define inf (open-input-file "test.txt"))
(define mystring (readline inf))
(define lineno 1)
  
(while (not (eof-object? mystring))
   (display "Line ")
   (display lineno)
   (display ": ")
   (display mystring)
   (newline)
   (set! mystring (readline inf))
   (set! lineno (+ lineno 1))
)

The preceding code produces just the right output:

[slitt@mydesk scheme_guile]$ ./readwrite.scm
Line 1: Steve was here
Line 2: and now is gone
Line 3: but left his name
Line 4: to carry on.
[slitt@mydesk scheme_guile]$

I'm sure Scheme gives you a much better way to read a line at a time than the preceding hackaround, but at least you know one way or another you can do it.

#!/usr/bin/guile
!#

(define readline
   (lambda (infile)
      (define c "initialization")
      (define returnstring "")
      (while #t
         (set! c (read-char infile))
         (if (eof-object? c) (break))
         (if (char=? c #\newline) (break))
         (set! returnstring (string-append returnstring (string c)))
      )
      (if (eof-object? c)
         c
         returnstring
      )
   )
)

(define ouf1 (open-output-file "out1.jnk"))
(define ouf2 (open-output-file "out2.jnk"))
(define inf (open-input-file "test.txt"))
(define mystring (readline inf))
(define lineno 1)
(define outstring "fingerinit")
  
(while (not (eof-object? mystring))
   (set! outstring "Line ")
   (set! outstring (string-append outstring (number->string lineno)))
   (set! outstring (string-append outstring ":: "))
   (set! outstring (string-append outstring mystring))
   (set! outstring (string-append outstring (string #\newline)))
   (if (= (modulo lineno 2) 1)
      (display outstring ouf1);
      (display outstring ouf2);
   )
   (set! mystring (readline inf))
   (set! lineno (+ lineno 1))
)

(close-output-port ouf1)
(close-output-port ouf2)
(close-input-port inf)

The preceding program produces the following out1.jnk and out2.jnk output files:

[slitt@mydesk scheme_guile]$ cat out1.jnk 
Line 1:: Steve was here
Line 3:: but left his name
[slitt@mydesk scheme_guile]$ cat out2.jnk 
Line 2:: and now is gone
Line 4:: to carry on.
[slitt@mydesk scheme_guile]$

Kludge: Printing Decimals

I love that Scheme preserves exact fractions til the bitter end, but none of the documentation I read explains how to print those immense fractions as simple decimal numbers. So I made a procedure to display a number in decimal format, even if internally it's represented as a fraction. This procedure is a kludge, and it's also not accurate in the rightmost digit because the rightmost digit is truncated instead of  rounded. It also won't work for negative numbers. I'd like very much if someone would email me with the real way to display a fraction in as a decimal, but til then, here's my kludge:

#!/usr/bin/guile
!#

(define display-only-decimal
   (lambda (n precision)
      (let ((whole 0) (decimal 0))
	 (set! n (* n 10))
	 (set! whole (truncate n))
         (display whole)
	 (set! decimal (- n whole))
         (if (<= precision 1)
            #t
            (display-only-decimal decimal (- precision 1))
         )
      )
   )
)
      

(define display-as-decimal
   (lambda (n precision)
      (let* ((wholenumber (truncate n)) (decimal (- n wholenumber)))
         (display wholenumber)
         (display ".")
	 (display-only-decimal (- n wholenumber) precision)
      )
   )
)

(define n 9990)
(while (< n  10010)
    (display (/ n 10000)) (display " ::: ")
    (display-as-decimal (/ n 10000) 6) (newline)
    (set! n (+ n 1))
)
[slitt@mydesk scheme_guile]$ ./decimal.scm 
999/1000 ::: 0.999000
9991/10000 ::: 0.999100
1249/1250 ::: 0.999200
9993/10000 ::: 0.999300
4997/5000 ::: 0.999400
1999/2000 ::: 0.999500
2499/2500 ::: 0.999600
9997/10000 ::: 0.999700
4999/5000 ::: 0.999800
9999/10000 ::: 0.999900
1 ::: 1.000000
10001/10000 ::: 1.000100
5001/5000 ::: 1.000200
10003/10000 ::: 1.000300
2501/2500 ::: 1.000400
2001/2000 ::: 1.000500
5003/5000 ::: 1.000600
10007/10000 ::: 1.000700
1251/1250 ::: 1.000800
10009/10000 ::: 1.000900
[slitt@mydesk scheme_guile]$

Basically, you call display-as-decimal with the non-negative number to be displayed, and the number of decimal places you want to show after the dot. display-as-decimal displays the whole part of the number and the dot, and then calls recursive subroutine display-only-decimal to display the proper fractional part as a decimal.

Kludge city, but if nobody comes up with a real Scheme way to do this, it's the best I've got (other than reworking it so it works with negatives and rounds the last digit).

Random Numbers in Scheme (Guile implementation)

Many applications require random numbers. Games of chance. Games where the initial state must be random (chicklet puzzle, for instance). Here's how you do random numbers in the Guile implementation of Scheme:

#!/usr/bin/guile
!#

; You want to seed the random number generator with a number based on
; the clock, but varying widely from second to second, both absolutely
; and proportionally. You also want the
; range of possible numbers to be wide enough that you can run the
; program many, many times without encountering the same sequence of
; random numbers.
;
; To do this, you square the seconds from epoch, then remove all digits
; but the last five. As long as you don't run the program twice in a
; second, the seed will vary wildly between runs.
;
; The following statement implements this, and the statement after it
; displays the seed.
(define myseed (modulo (* (current-time) (current-time)) 100000))
(display "Myseed = ") (display myseed) (newline)

; Random functions in Scheme require a state variable in order to
; eliminate repeatability between runs. The following statement sets
; just such a state, based on the seed calculated previously.
(define randstate (seed->random-state myseed))

; Run a loop to issue 20 random numbers between 0 and 99
(define n 0)
(while (< n 20)
    ; random 99 produces numbers beween 0 and 99.
    ; Randstate is included so numbers depend on seed calculated with
    ; clock.
    (display (random 99 randstate)) (newline)

    (set! n (+ n 1))
)
[slitt@mydesk scheme_guile]$ ./rand.scm
Myseed = 20841
51
42
29
2
28
49
20
68
22
24
42
47
44
27
39
50
38
42
71
77
[slitt@mydesk scheme_guile]$

Verify that if you run it and then run it again 2 seconds later, you get completely different results. Don't worry too much if you get multiple copies of the same number. The chance of getting no repeats is:

((range * (range - 1) * (range - 2) ... (range - n))/rangen

Here's a little Scheme program to calculate the likelihood of zero repeats, expressed as a percentage, where it's invoked by:

./chance.scm number_of_runs range

In our case n is 20 and range is 100. The following shows the program, and how it runs with a range of 100 and various values of n:

#!/usr/bin/guile
!#

(define display-only-decimal
   (lambda (n precision)
      (let ((whole 0) (decimal 0))
	 (set! n (* n 10))
	 (set! whole (truncate n))
         (display whole)
	 (set! decimal (- n whole))
         (if (<= precision 1)
            #t
            (display-only-decimal decimal (- precision 1))
         )
      )
   )
)
      
(define display-as-decimal
   (lambda (n precision)
      (let* ((wholenumber (truncate n)) (decimal (- n wholenumber)))
         (display wholenumber)
         (display ".")
	 (display-only-decimal (- n wholenumber) precision)
      )
   )
)

(define argv (command-line))
(define argc (length argv))
(define n (string->number (list-ref argv 1)))
(define range (string->number(list-ref argv 2)))
(display "n is ") (display n) (newline)
(display "range is ") (display range) (newline)

(define accum 1)
(define ss 0)
(while (< ss n)
   (set! accum (* accum (/ (- range ss) range)))
   (set! ss (+ ss 1))
)

(display "Chance of no repeats is: ")
(display-as-decimal (* accum 100) 4)
(display "%\n")
(newline)

The previous code produces the following output when run on numbers 1, 2, 5, 10, 15, 20, 25, 30, 35 and 40, with range of 100:

[slitt@mydesk scheme_guile]$ ./chance.scm 1 100
n is 1
range is 100
Chance of no repeats is: 100.0000%

[slitt@mydesk scheme_guile]$ ./chance.scm 2 100
n is 2
range is 100
Chance of no repeats is: 99.0000%

[slitt@mydesk scheme_guile]$ ./chance.scm 5 100
n is 5
range is 100
Chance of no repeats is: 90.3450%

[slitt@mydesk scheme_guile]$ ./chance.scm 10 100
n is 10
range is 100
Chance of no repeats is: 62.8156%

[slitt@mydesk scheme_guile]$ ./chance.scm 15 100
n is 15
range is 100
Chance of no repeats is: 33.1284%

[slitt@mydesk scheme_guile]$ ./chance.scm 20 100
n is 20
range is 100
Chance of no repeats is: 13.0399%

[slitt@mydesk scheme_guile]$ ./chance.scm 25 100
n is 25
range is 100
Chance of no repeats is: 3.7617%

[slitt@mydesk scheme_guile]$ ./chance.scm 30 100
n is 30
range is 100
Chance of no repeats is: 0.7791%

[slitt@mydesk scheme_guile]$ ./chance.scm 35 100
n is 35
range is 100
Chance of no repeats is: 0.1131%

[slitt@mydesk scheme_guile]$ ./chance.scm 40 100
n is 40
range is 100
Chance of no repeats is: 0.0112%

[slitt@mydesk scheme_guile]$

The following table lists the precentage chance for no dups in a run with range 100, and the percentages are rounded (by hand) by manually dropping a digit and rounding the one before it. 

nChance of
no dups
(in percent)
1100%
299.000%
590.346%
1062.816%
1533.128%
2013.040%
253.762%
300.779%
350.113%
400.011%

You can see that with a range of 100, you have a 50/50 chance of getting a dup somewhere between 10 and 15 numbers. By the time you're outputting 20 numbers, your chance of no dups is only 14%. So don't assume your randomization routine is bad just because you get dups -- outputting 20 numbers with a range of 100 there's an 87% likelihood you will get at least one dup.