Comp 210 Lab 2: Stepping; Lists

Table of Contents

  • Hand-evaluating a Program
  • Step by Step
  • The UNIX Corner
  • Hand-evaluating expressions

    As featured in Wednesday's lecture, the below should make sense to you. Try typing them into Donkey, and make sure the results are what you expect:
    null
    (cons 3 null)
    (cons 'one (cons 2 (cons 3 null)))
    
    (define l2 (cons 2 (cons 3 null)))
    l2
    (null? l2)
    (car l2)
    (cdr l2)
    (car (cdr l2))
    (cdr (cdr l2))
    (null? (cdr (cdr l2)))
    (cdr (cdr (cdr l2)))
    (cons 2 3)
    
    You should be able to guess the results of evaluating each of the above expressions.

    An aside: symbols (like 'one above) are simple values, like numbers and #f and #t. Except that where a bunch of functions (like +, sqrt) work on numbers, and a few (if,and,or) work on boolean values, there is only one function which concerns itself explicitly with symbols: eq?. (They're almost too simple!) Remember that = compares numbers while eq? compares symbols. For kicks, you can try (= 'same 'same).

    Just by taking things one step at a time, we can evaluate (car (cdr l2)) Remembering to write an equal sign between expressions which are equal (and remembering which parentheses go with each expression),

      (car (cdr l2))
    = (car (cdr (cons 2 (cons 3 null))))
    = (car (cons 3 null))
    = 3
    

    This same idea of hand evaluation (by just replacing expressions with equivalent expressions) can be applied to functions.

    (define square
      (lambda (n)
        (* n n)))
    
    (define dist
      (lambda (x y)
        (sqrt (+ (square x) (square y)))))
    
    (dist 24 7)
    
    You can start to hand-evaluate (dist 24 7), but you can see that really there are quite a few steps involved: First we have to evaluate the placeholder dist, and replace it by its value (the lambda expression). Then, we have to re-write the body of the lambda, substituting 7 and 24 for x and y. Then we have the sub-problem of evaluating (square 7)...what a pain! Gee, it would be nice if the computer would do this step-by-step evaluating for us.

    Step by Step

    If you want to see the computer walk through your program in "slow motion", step-by-step, you can use Donkey's "step" button. You might find this helpful in the future, to find out exactly why your program is doing what it does, especially when you expected something else.

    Let's try it: type (dist 24 7) and press the "Step" once. This adds a few more buttons, and fills the "Next Step" window with what will happen when "step" is clicked again. In this case, it replaces a symbol (dist) with that symbol's value (a lambda expression). Click "Step" to see this happen before your eyes.

    Some things to observe:

  • You can also click the Unstep button.
  • While interesting (and necessary for understanding) to see every eensy-weensy step that Scheme makes, it can also be boring, or you might be interested in only showing intermediate evaluations at certain points, such as every time a recursive call is made.

    You can modify what steps cause Donkey to stop at via (surprise surprise) the Stop At menu. Instead of ``all'', select ``primitives'' instead. Now type (dist 24 7) and step through it. This time, Donkey only pauses whenever a primitive (that is, built-in) function is called.

    The complement of this can be more useful: Stopping at "apply" means that Donkey pauses before calling any functions you defined (in this case, dist and square

  • Finally, let's step through one more example.

    (define last
      (lambda (nel)
        (if (null? (cdr nel))
            (car nel)
            (last (cdr nel)))))
    
    This is a function designed to take a non-empty list as input. It is a bit strange, in that the definition of this function last itself calls the function last! We'll talk more about this phenomonen, recursion, in lecture.

    For now, type in the above function. (Actually, if you're looking at this in netscape, you can use the mouse to cut-and-paste the code from Netscape into Donkey.) Let's see what's involved with evaluating
    (last (cons 'aloha (cons 'konnichi-wa (cons 'hey null))))
    step-by-step. First, use Donkey to stop at every steps. In particular, note the several steps involved in resolving the if statement.

    Again, that long series of steps was fascinating, but sometimes we might not want all that detail. Step through this same evaluation again, stopping only at functions we defined (which in this case is always just "last"). This gives a better feel as to how the code accomplishes its task.

    The UNIX Corner: the Filesystem

    The handout for Lab 1 gave an introduction to the UNIX file system. We'll build on that here by mentioning a few more commands in more detail.
  • ls Some useful flags to ls are -a, which lists all files. Normally, files whose name begins with the character ``.'' are ignored by ls as uninteresting.

    The -l flag (as mentioned in the Lab 1 handout) gives the long listing of files, including the size, owner's name, and permission privileges for that file. The meaning of those permission codes, and a more full explanation of how to use chmod to change them, will be talked about in lab, and is also covered in Owlnet's UNIX handout.

  • mkdir, rmdir As mentioned in the Lab 1 handout, mkdir command makes a new directory. You can remove a directory with rmdir, but you must remove all the directory's files first (with rm). Of course, you can make directories within directories; for instance after changing directories to ~/comp210, you can then mkdir hw2 and mkdir hw3 to further categorize your files.
  • pwd To find out where you currently are in the filesystem, pwd will print your working directory.
  • cp, mv These commands copy and move files, respectively. Note that moving a file is the same as renaming it; there isn't a seperate rename command.

    Both cp and mv share a similar syntax; we use cp to illustrate, but the below holds for mv as well.

    You can copy one file to another by saying cp oneFile another. (Try making a copy of your homework file, naming the copy test.ss.) If the file another already exists, it will be overwritten, and lost forever. (One special case is that if another already exists but is a directory, then the directory is not overwritten, and instead a copy of oneFile is put inside another/.) You can also copy many files all to the same directory at once: cp file1 file2 file3 file4 targetDir.

    The -i flag (``interactive''?) provides some protection for you; it causes cp or mv to ask before deleting a file. You may have already seen this behavior; type which cp for a clue as to why!

    In order to copy an entire directory to a new name, you must use the -r flag to recursively copy all the files inside that directory (including any of those files that are themselves directories). (This does not apply to mv.)

  • rm To remove files, use rm, but with caution: once a file is deleted, it is gone from the disk! You might be able to get the file backed up from tape, but only if the file has been around for a while. Fortunately, your rm is initially set up to use the -i flag, which acts as it does for cp and mv. The -r (recursive) flag works for rm as well, but be very careful--rm -r \~ will speedily delete all your files!, and unfortunately there is no Trash Can in UNIX -- a deleted file is gone for good (well, Owlnet might have an old version backed up).
  • man If you've forgetten exactly which arcane flag to (say) ls causes it to indicate directories by appending a slash to the name, you can always look it up in the manual: try man ls. (The answer is -F.) The on-line manual pages are famous for not being particularly helpful in learning about UNIX overall, and it has more obscure details than any sane person would want to know, but it is handy to remind yourself of what flags a program takes, and what they do.

    Will man man cause an infinite loop?

  • alias You can use alias to give a new (shorter) name to another existing command. For instance, I like alias ls ls -F. For the rest of the time I am logged in, whenever I type (say) ls ~comp210, the command that really gets issued is ls -F ~comp210. To cancel an alias you've made, use unalias: For instance, unalias ls.

    This concept may not seem to have too much potential, but some idiots go beserk over it. For instance, check out the file ~ian/.aliases.

    For aliases that you like to use all the time, you can actually put that above alias command at the end of your file ~/.cshrc. This is a special file whose commands are executed every time you log in. (In fact, it is through this file that a system-wide file is executed for you; this system-wide file contains the command alias cp cp -i Aha!) Self-exercises:

    1. What is the absolute pathname for comp210? For your home directory?
    2. From your home directory, what is the relative pathname of the comp210 directory? Use ls to verify your guess.
    3. List the files of the comp210's homework directory, find what the file is named which has the hw1 solutions, and copy it to a file named my-copy.ss in your comp210 directory.
    4. Find exactly the line in the system-wide file which aliases cp for you. If you were to decide you didn't want this behaviour of cp, how would you nullify it? (I don't recommend actually doing this, but it's empowering to know how.)

    Back to Comp 210 Home