Getting Started with Scheme

1. Introduction

Scheme used to be the first language CS majors at MIT, UC Berkeley, and other noteable institutions would be taught. Today, a number of those CS programs start with Python.

Scheme is noteworthy for a number of reasons that are beyond the scope of this lesson. It has a minimal syntax, which makes getting started easy.

2. Hello, World!

On to our obligatory first exercise in a new language: Writing a program to print Hello, world! . We'll leverage an online Scheme interpreter to run our programs. Open http://repl.it/languages/Scheme in a new tab.

The interactive BiwaScheme interpreter hosted at http://repl.it will interpret each statement as it's entered. Try typing this:

   
Hello, world!
   
  

You should have gotten an error, as raw text is not a valid statement. How about this?

   
"Hello, world!"
   
  

The expression above has a value , as a string. The value is echoed (printed) back to you by the interpreter, which parses your statement and prints the resulting value.

3. Variables

If you type x and press [Enter], you're informed that x is an unbound symbol , meaning that the variable x isn't tied (bound) to any value. Let's declare and initialize the variable x :

   
(define x 2)
   
  

What's stored in x ? Type this statement to see:

   
x
   
  

We stored a number in x . How about strings?

   
(define words "I like cat food.")
words
   
  

We didn't have to declare that x and words would hold numbers and strings, respectively. That's because Scheme determines the data type that is needed for us. That makes Scheme loosely typed , whereas Java is referred to as strictly typed , meaning we have to specify the data type for variables we use.

4. Simple math, operator-operand order

In Java, we used basic arithmetic operators -- +, -, *, / -- quite a bit. We typically have expressions like 2 * 3 as in this Java statement:

   
System.out.println( 2 * 3 );
   
  

Scheme has a different order for operators and operands. While in Java a binary operator (like * ) requires the order by operand_1 operator operand_2 , Scheme's syntax requires the operator to go first. Try these:

   
(* 2 3)
(+ 5 -1)

;comments start with semi colons
;you can nest these statements:
(+ (* 2 3) (- 8 6))
;just like in math, innermost ()s are evaluated first

;are 3 operands OK?
(+ 1 2 3)
   
  

You might notice the Scheme interpreter helping you make sure you close all open parentheses by highlighting matching pairs of parentheses as you type. One of the frustrating features of Scheme for beginners is the number of parentheses that are sometimes needed for complex statements. Stay tuned...

5. Exercises

  1. Ask Scheme to compute the average of the values in this set: { 52, 29 }
  2. Compute the sum of the values in this set: { 52, 29 , 106 }
  3. Compute the average of the values in this set: { 52, 29 , 106 }
  4. How would you rewrite this expression more concisely (i.e., with fewer operators/parentheses)? (* (* 4 3) 2)

6. Functions

In Java, we often talk about methods as sets of instructions that deal with input data (an argument, value in a field, etc.) and have some kind of effect like changing a field's value or returning data (object or primitive value). In Scheme, we define functions. (There's a longer form that involves the use of lambda that I'm not including here.)

Here's an example of a function that takes in a value that we'll call n and returns that number times 5:

   
(define (timestwo n) (* 2 n))
   
  

You call a function in this manner:

   
(timestwo 6)
;printed result is 12
   
  

You can even write a function in terms of another:

   
(define (timeseight n) (* (timestwo n) 4))

;call the function:
(timeseight 3)
   
  

7. Conditionals

if and cond are common conditionals used in Scheme.

7.1. if

In Java, we may have if() used in this way:

   
int x = 10;

if( x < 16 ) {
    System.out.println("x less than 16");
} else {
    System.out.println("x is at least 16");
}
   
  

Here's the equivalent set of statements in Scheme:

   
(define x 10)
(if (< x 16) (print "x less than 16") (print "x is at least 16"))
   
  

For readability, you might use multiple lines to write the if statement:

   
(if (< x 16) 
  (print "x less than 16") 
  (print "x is at least 16"))
   
  

As you might have surmised, the statement to run if the condition is true appears right after the condition, while the "else" statement appears next. Here is Scheme's syntax for if statements:

(if (condition) (then ...) [(else...)] )

Note that the else portion is in square brackets since it's optional -- just like else isn't required for if() statements in Java.

7.2. cond

Sometimes there are more than just two cases we need a program to react to. In Java, if() handles one case (condition is true), while if()-else handles two cases (condition is true or false). When there are more cases, Java provides if()-else if()-else . Scheme can do similar using nested if statements:

   
(define x 0)
(if (< x 0)
    (print "x is negative")
    (if (> x 0)
        (print "x is positive")
        (print "x is zero")))
   
  

Yuck! There has to be a better way. Enter cond :

   
(define x 0)
(cond
    ((< x 0) (print "x is negative"))
    ((> x 0) (print "x is positive"))
    (print "x is zero"))
   
  

Notice now the last condition doesn't have a boolean like (= x 0) -- it's treated as an else . And that "else" is optional.

See another example of cond here .

8. Fibonacci, Recursively

One of the greatest strengths of Scheme is the ease with which recursion can be expressed. Consider Fibonacci numbers, which are the elements of the set
{ 1, 1, 2, 3, 5, 8, 13, ... } .
Earlier this year, we wrote a recursive method to find the $n^{th}$ Fibonacci number:

   
/*
 * Find the n^th Fibonacci number.
 * Precondition:  n >= 0
 */
public static int fibRec(int n) {
    //base cases:
    if ( n == 0 || n == 1 ) {
        return 1;
    }

    //this fib # is sum of the two prior fib #s:
    return fibRec(n-1) + fibRec(n-2);
}
   
  

Simplifying the method to make our job in Scheme a little easier, we get

   
public static int fibRec(int n) {
    if ( n < 2 ) {
        return 1;
    } else {
        return fibRec(n-1) + fibRec(n-2);
    }
}
   
  

Try this in Scheme:

   
(define (fib n) 
   (if (< n 2) 
     1 
     (+ (fib (- n 1)) (fib (- n 2)))))

;does it work?  expect { 1, 1, 2, 3, 5 }
(fib 0) 
(fib 1)
(fib 2)
(fib 3)
(fib 4)
   
  

9. Iteration that Looks Like Recursion

9.1 Counting down

Want to write a program that counts down from n to 1? We'd typically write Java like so:

   
public static void countDownFrom(int n) {
    while( n > 0 ) {
        System.out.println( n );
        n--;
    }
}
   
  

If we considered a recursive version of the method, it might look like this:

   
public static void countDownFromRec(int n) {
    System.out.println( n );

    //base case:
    if( n == 1 ) {
        return;
    }

    countDownFromRec( n - 1 );
}
   
  

In Scheme, we'd typically write a method that calls itself (recursion) to accomplish this task:

   
(define (countDownFrom n) 
  (if (= n 1)
    (print 1) 
    (begin 
      (print n)
      (countDownFrom (- n 1)))))

(countDownFrom 5)
   
  

(Note the use of begin , which groups multiple statements together to run one after the other.)

9.2 Counting up

Since counting down is typically easier for recursion, counting up is presented afterward. It's best for the user to call the procedure like this -- (countUpTo 10) -- but in actuality the procedure will need to take two arguments. This is where a helper procedure comes in handy:

   
(define (countUpTo n)
  (countUpToHelper 1 n))

(define (countUpToHelper a n)
  (if (= a n)
    (print a)
    (begin
      (print a)
      (countUpToHelper (+ a 1) n))))

(countUpTo 10)
   
  

10. A Few Exercises

  1. Write a function that converts a degree measure to radians:

         
    (define (deg->rad deg) ???)
    
    (deg->rad 180)               ;approx 3.141592653
    (sin (deg->rad 30))          ;0.5
         
        
  2. Write a recursive function that returns the sum of squares up to n :

         
    (define (sum_of_squares n) ???)
    
    (sum_of_squares 5)           ;55, the value of 
                                 ;1^2 + 2^2 + 3^2 + 4^2 + 5^2
         
        
  3. Write a recursive function that raises a base to a power:

         
    (define (exp a b) ???)
    
    (exp 2 5)                    ;32, value of 2^5
    (exp 3 0)                    ;1, value of 3^0
         
        
  4. Scheme has a built-in function for modulo. Try it: (mod 14 4) . Write your own modulo function:

         
    (define (% m n) ???)
         
        

11. Resources

  1. An excellent and free intro-to-CS book, Structure and Interpretation of Computer Programs ( SICP for short) is available at http://mitpress.mit.edu/sicp/full-text/sicp/book/book.html .
  2. A listing of Scheme statements supported by BiwaScheme is available at http://www.biwascheme.org/doc/reference.html .