Index: Donkey, How to print homeworks, Scheme style, Scheme Syntax
Like DrScheme, Donkey is a programming environment for Scheme. While DrScheme is generally better, Donkey has one important feature that DrScheme lacks: it allows you to see how your program is evaluated. This lab shows you how to use that feature.
To run Donkey, either
As an example, type (if (= 1 2) (+ 1 2) (+ 1 3)) in the main window.
When stepping, you also have other options, e.g., selecting the Unstep button goes backwards one step in the evaluation.
Since stepping through larger programs can be very tedious, you can indicate what kinds of subexpressions are "important" to show during stepping. In the Stop-at menu, currently All is selected, i.e., stepping stops at all subexpressions. If you select "if/cond/case", stepping will only stop and conditionals, but not at function applications.
The other main option you'll want in Donkey are to Load files (in the File menu). We assume you'll usually use DrScheme for writing your programs. Select Help from the Help menu to explain other options.
Try stepping through some examples. In particular, try a simple use of recursion:
(define length (lambda (l) (cond ((null? l) 0) (else (+ 1 (length (cdr l))))))) (length (list 1 4 8 2))Observe how a bunch (hmm... a stack?) of additions pile up waiting for you to calculate the length of the rest of the list.
When stepping through recursive functions, you sometimes want to select only "apply" in the Stop-at menu, i.e., only indicate when it's applying a user-defined function and skip over the conditionals and primitive functions.
Students have asked how best to print their homeworks, including testing, for grading. We suggest the following:
Like any language, there are conventions for writing Scheme that help make it more readable. In this lab and the previous one, we've discussed some conventions on providing supplementary information in comments. In class, we briefly discussed conventions for choosing between cond and if. Here, we will discuss layout and indenting conventions. Also of note, programmers vary widely in naming conventions, e.g., whether to name a list of numbers as l, lon, AListOfNumbers, nums, or something else.
The basic goals of spacing and indentation in Scheme include
(define afunction (lambda (x) body))The define and lambda keywords are each on separate lines to point out that you are 1) making a definition and 2) creating a function of one variable.
(if (= 3 x) (f 5) (+ 7 y))The "then" and "else" branches are on separate lines and aligned so that you can easily see them. The same idea holds for larger conditionals:
(cond ((null? l) 0) (else (+ 1 (foo (cdr l)))))(Note that I like to also align the result expressions in a cond, assuming the test expressions are reasonably short.)
When subexpressions are long, or so deeply nested that you're regularly using 60+ columns of characters, you may have to break lines more frequently, e.g.,
(cond ((null? l) 0) (else (+ 1 (foo (cdr l)))))or in function calls,
(myfunction (+ 3 (* 5 x) y) (- 3 (f 9 z)))
Note that using too many lines obscures structure:
(define afunction (lambda (l) (cond ((null? l) 0) (else (+ 1 (afunction (cdr l)))))))It also makes you scroll vertically more.
Let's go over Scheme's syntax again, with emphasis on the common problem of "where do parentheses go?".
Expressions can be constants, e.g.,
Expressions can be function applications:
Expressions can be special forms. Special forms are not function applications. In many languages, most expressions are special forms and thus are not "special". In Scheme, these are considered the exceptions to the general case of the function call. So far we've seen the following:
Looking at the above, parentheses can mean one of three things (given this subset of Scheme):