Racket Introductory Lab

This is an individual assignment. Work through the following lab. There are two portions that you need to turn in, labeled with "***":

Keep in mind that in addition to this lab, there are Racket and Scheme resources linked on the course page if you need help.

There are other questions intermixed throughout the lab for you to think about. You do not need to turn in answers to these. Ask in class if the answers aren't clear.

Part 1: Getting started in DrRacket

  1. Start up DrRacket, which is the programming environment that we'll be using. You'll find in the department virtual machine, which you can access via VirtualBox. If you want to install the virtual machine on your own computer, follow the instructions on the course web page.
  2. If this is the first time you're starting up DrRacket, you'll see a warning about no language being specified. You can ignore it, and all will work; alternatively, you can go to the Languages menu for DrRacket, select "Choose Language," and make sure the first option is selected, which says "Start your program with #lang..."

  3. You will see a pair of windows. The bottom window says "Welcome to DrRacket." That is the interactions window. This is where you can test statements to see what they will do. Try it out - in the interactions window, type

    (+ 3 5)

    This should add 3 to 5. In Racket, + is a function. To call a function in Racket, you place the name of the function and its arguments, separated by spaces, inside parentheses. This takes a little getting used to! In most programming languages, function calls look something like this:

    function(arg1, arg2, arg3)

    In Racket, function calls look like this:

    (function arg1 arg2 arg3)

  4. Change your program in some way. For example, re-type it as

    (+ 3 7)

  5. Experiment with hitting the Esc key followed by either the p or the n keys, which allow you to move backwards and forwards through your command history.

Part 2: Basic Racket Primitives

  1. In the interactions window, enter the following:

    (car '(apple orange pineapple))
    (cdr '(apple orange pineapple))
    (car (apple orange pineapple))
    

    What do car and cdr do? Why is the single quote necessary? What does it do? The last line of the above should cause an error: why?

  2. *** Write sequences of cars and cdrs that will pick the symbol 'pear out of the following expressions:

    (apple orange pear grapefruit)
    (((apple) (orange) (pear) (grapefruit)))
    (apple (orange) ((pear)) (((grapefruit))))
    

    It's ok if you have trouble getting this to work: the key aspect to this assignment is to make the effort before the next class. Turn in your best attempts.

  3. Execute the following statements. What do the functions cons, append, and list do?

    ;; This is a comment, by the way!
    (cons 'x '(1 2))
    (cons '(1 5) '(2 3))
    (append '(1) '(2 3))
    (append '(1 5) '(2 3))
    (list '1 '2 '3 '(4 5))
    
  4. Execute the following code. What do length and reverse do?

    (length '(plato socrates aristotle))
    (reverse '(plato socrates aristotle))
    (member 'socrates '(plato socrates aristotle))
    (member 'raphael '(plato socrates aristotle))
    

Part 3: Saving your code

Entering your code interactively is fun, but not a good idea for creating large programs. A better way to go is to write your code, save it, then run it. Here's how to do it.

  1. In the host Mac operating system (not in the Linux VM), open up a Mac finder window, find the Applications folder, and then double click on the program "Mount Network Drives". Enter your username and password to map your campus directory. Once you've done so, go back to your Linux VM and make yourself a directory to store your files:

    cd HOME251
    mkdir cs251
    cd cs251
    mkdir racket
    cd racket
    
  2. Start typing in some Racket code in the definitions window at the top of the screen. Make sure that the first line says:

    #lang racket
    
    Use any of the above examples that you wish. When finished, save your program by going to the File menu, and choosing Save Definitions.

  3. Run your program by clicking on the clicking on the Run button, or by using the combination Ctrl-T.

    You should generally use this approach for entering and running Racket code, but entering code directly into the interactions window is good for testing out quick ideas.

Part 4: Conditionals

Racket has a number of different predicates for testing equality.
  1. Try this code:

    (equal? '(hi there) '(hi there))
    (equal? '(hi there) '(bye now))
    (equal? 3 3)
    (equal? 3 (+ 2 1))
    (equal? 3 3.0)
    (equal? 3 (/ 6 2))
    (equal? -1/2 -0.5)
    (eqv? '(hi there) '(hi there))
    (eqv? '(hi there) '(bye now))
    (eqv? 3 3)
    (eqv? 3 (+ 2 1))
    (eqv? 3 3.0)
    (eqv? 3 (/ 6 2))
    (eqv? -1/2 -0.5)
    (= 3 3)
    (= 3 (+ 2 1))
    (= 3 3.0)
    (= 3 (/ 6 2))
    (= -1/2 -0.5)
    (= '(hi there) '(hi there))  ;; yes, this will give an error
    

    What kind of responses do you get? How are equal?, eqv?, and = different?

  2. Enter the following code:

    (if (equal? 8 3)
        9
        10)
    

    Modify the condition following if to get a different value to return.

    [Note that Racket pays no attention whatsoever to how you indent your code. The above indenting is stylistically useful to see what the "if" function is doing, but you could technically indent it any way you like.]

  3. Enter the following code:

    (cond ((equal? 16 3) (+ 3 8))
          ((equal? 16 8) 12)
          (else (* 6 3)))
    

    Can you replace all of the 16's in the above code with some other value to change the return value? What does the cond function do?

Part 5: Defining functions

  1. In a new file, enter in the following code, save it, then run it.

    (lambda (x)
      (+ x 1))
    

    What does Racket return? The lambda function returns a function without a name. In this case, you have defined a function that takes a parameter and adds 1 to it. Functions are also called procedures.

  2. A function without a name is useless, as it is immediately garbage collected. Try this instead:

    (define add-one
      (lambda (x)
        (+ x 1)))
    

    Save this code, run it, then type (add-one 5) in the interactions window. The define statement created a pointer, called add-one, which points to the function you just created.

  3. Try this out:

    (define another-add-one add-one)
    (another-add-one 5)
    

    At the pointer level, what is happening here? Draw a picture on this paper indicating what is happening.

  4. You can declare "local" variables in Racket via the use of the let function. For example, try the following code:

    (define a 5)
    (define b 6)
    (define c 7)
    (define strange
      (lambda (x)
        (let ((a 1) (b 2))
          (+ x a b))))
    

    After executing this code, what are the values of a, b, and c? What about what you get when you make the call (strange 3)? Why?

Part 6: Recursion

  1. Enter and load the following function. What does it do? Why?

    (define mystery
      (lambda (L)
        (if (null? L)
            L
            (append (mystery (cdr L))
                    (list (car L))))))
    

    Note that there is no return statement here, as you would find in other languages you may know. Why? How is the return value determined in the above function?

  2. To watch your program in action with the debugger, click the "Debug" button instead of the "Run" button. Then rerun your program by typing (in the interactions window)

    (mystery '((1 2) (3 4) 5 6))
    

    A series of debugging buttons will appear at the top of the definitions window. Click "Step" repeatedly, and watch the pointer move through your code. Also watch the gray bar to the far left of the debugging buttons. DrRacket will show you the return values for functions when they are called. You can also hover your mouse over variables (hover the mouse over the variable L, for example), and DrRacket will show you those variable values to the right of the debugging buttons. You can also see the stack of function calls and variable values to the right.

    You can use the "Go" button to resume execution of your program.

  3. Modify the program as follows:

    (define mystery
      (lambda (L)
        (if (null? L)
            L
    	(begin
    	  (displayln L)
              (append (mystery (cdr L))
    	          (list (car L)))))))
    

    What does begin do? What does displayln do?

  4. *** Write a recursive function, keep-first-n, that returns a list of the first n elements in a list.

    Example:

    > (keep-first-n 3 '(a b c d e f g h i))
    (a b c)
    

    Your code should do something appropriate if n is too big or too small (negative). It doesn't matter to me precisely what it does under these circumstances, so long as it does something reasonable (doesn't crash or return complete nonsense).

    Your function should not use any other Racket functions than those which have been introduced in this lab. [An exception: if you wish, you may use the functions <, >, <=, or >=.]

  5. *** Write a recursive function named sum that adds up all the elements in a list. For example:

    (sum '(4 5 0 1)) ---> 10
    

    Do something reasonable if the list is empty.