- Held
- Friday, 8 March 2019
- Writeup due
- Monday, 11 March 2019
- Summary
- In this laboratory, we start to explore the DrRacket debugger.

a. Make sure that the `loudhum`

package is up to date.

b. Require the `rackunit`

and `rackunit/text-ui`

packages.

c. Add the following undocumented code to your definitions pane.

```
(define numbers '(3 7 8 6 16 19 12 0 4 5 17 15 11 13 1 9 14 2 10 18))
(define sum (section reduce + <>))
(define smallest (section reduce min <>))
(define largest (section reduce max <>))
(define second-smallest
(lambda (numbers)
(list-ref (sort numbers <) 2)))
(define second-largest
(lambda (numbers)
(list-ref (sort numbers >) 2)))
;;; Procedure:
;;; average-w/o-extremes
;;; Parameters:
;;; numbers, a nonempty list of real numbers
;;; Purpose:
;;; Computes the average of numbers after dropping the two highest and two lowest
;;; Produces:
;;; avg, a real number
;;; Preconditions:
;;; * (length numbers) is greater than 4
;;; Postconditions:
;;; * If max1, max2, min1, min2, are the largest, second largest,
;;; smallest, and second smallest values in numbers, respectively,
;;; then avg is the average of all the values in numbers excluding
;;; max1, max2, min1, min2
;;; * If all values in numbers are exact, then avg is exact
;;; * If at least one value in numbers is inexact, then avg is inexact
(define average-w/o-extremes
(lambda (numbers)
(/ (- (sum numbers)
(smallest numbers)
(second-smallest numbers)
(largest numbers)
(second-largest numbers))
(- (length numbers) 4))))
;;; Procedure:
;;; drop-to-first-zero
;;; Parameters:
;;; lst, a list of numbers
;;; Purpose:
;;; Removes all of the elements up to and including the first zero.
;;; Produces:
;;; newlst, a list of numbers
;;; Preconditions:
;;; The list contains at least one zero.
;;; Postconditions:
;;; Suppose the first zero is at index z.
;;; (length newlst) = (- (length lst) z 1)
;;; For all i s.t. z < i < (length lst)
;;; (list-ref newlst (- i z 1)) = (list-ref lst z)
(define drop-to-first-zero
(lambda (lst)
(drop lst
(index-of 0 lst))))
;;; Procedure:
;;; remove-below
;;; Parameters:
;;; num-lst, a list of real numbers
;;; threshold, a real number
;;; Purpose:
;;; Remove all numbers strictly below threshold from the list.
;;; Produces:
;;; newlst, a list of real numbers
;;; Preconditions:
;;; [No additional]
;;; Postconditions:
;;; The numbers below threshold have been dropped. That is, newlst contains
;;; no number x such that x < threshold.
;;; All other numbers have been retained. That is, if x appears k times in
;;; lst and x >= threshold, then x appears k times in newlst.
;;; No additional numbers are in newlst. That is, if x appears k times in
;;; newlst then x appears k times in lst.
(define remove-below
(lambda (num-lst threshold)
(map (section + <> threshold)
(drop-to-first-zero
(map (section - <> threshold)
(sort (append (list threshold) num-lst) <))))))
;;; Procedure:
;;; remove-above
;;; Parameters:
;;; num-lst, a list of real numbers
;;; threshold, a real number
;;; Purpose:
;;; Remove all numbers strictly above threshold from the list.
;;; Produces:
;;; newlst, a list of real numbers
;;; Preconditions:
;;; [No additional]
;;; Postconditions:
;;; The numbers above threshold have been dropped. That is, newlst contains
;;; no number x such that x > threshold.
;;; All other numbers have been retained. That is, if x appears k times in
;;; lst and x <= threshold, then x appears k times in newlst.
;;; No additional numbers are in newlst. That is, if x appears k times in
;;; newlst then x appears k times in lst.
(define remove-above
(lambda (num-lst threshold)
(map (section + <> threshold)
(drop-to-first-zero
(map (section - <> threshold)
(sort (append (list threshold) numbers) >))))))
;;; Procedure:
;;; filter-range
;;; Parameters:
;;; num-lst, a list of real numbers
;;; lower, a real number
;;; upper, a real number
;;; Purpose:
;;; Removes all numbers strictly below lower and strictly above upper from the list.
;;; Produces:
;;; newlst, a list of real numbers
;;; Preconditions:
;;; [No additional]
;;; Postconditions:
;;; The numbers outside the range have been dropped. That is, newlst contains
;;; no number x such that x < lower or x > upper.
;;; All other numbers have been retained. That is, if x appears k times in
;;; lst and lower <= x <= upper, then x appears k times in newlst.
;;; No additional numbers are in newlst. That is, if x appears k times in
;;; newlst then x appears k times in lst.
(define filter-range
(lambda (num-lst lower upper)
(remove-below
(remove-above num-lst upper)
lower)))
```

a. Suppose we were to call `(average-w/o-extremes '(5 -10 1 2 -11 4 3 22 12))`

. What expressions do you expect to be evaluated, and in what order? What values will they have?

b. Click the **Debug** button.

c. Click the **Go** button.

d. Right-click (or control-click) on the open parenthesis that begins
the body of `average-w/o-extremes`

. (The body is the line after the
parameter and begins with `(/`

.) Select “Pause at this point.”

e. In the interactions pane, type `(average-w/o-extremes '(5 -10 1 2 -11 4 3 22 12))`

and then hit **Enter**. If all goes well, the program will stop at the point you added a pause.

f. Using the **Step** button, see what order DrRacket follows in the
evaluation.

g. When the green triangle and green dot overlap, right click on the triangle and select “Print return value to console”. This allows you to explore what values expressions evaluate to and even change them with “Change return value…”

h. Summarize what information is and is not available while you step through the evaluation of the expression.

a. Write a test suite for `average-w/o-extremes`

. Your test suite should be
sufficiently robust that it is likely to identify an error in most
incorrect implementations of `average-w/o-extremes`

.

```
(define average-w/o-extremes-tests
(test-suite
"tests of average-w/o-extremes"
(test-case "lists of size 7"
(check-= (average-w/o-extremes (list 1 2 2 3 4 4 5)) 3 0)
(check-= (average-w/o-extremes (list 2 2 2 5 8 8 8)) 5 0))
...))
```

b. Run your test suite on the code provided at the beginning of the lab

```
> (run-tests average-w/o-extremes-tests)
```

c. If your test suite passes all the tests, add the following check to your test suite and run it again.

```
(check-= (average-w/o-extremes (list 1 2 5 5 5 6 7)) 5 0)
```

d. Using the debugger, figure out what is wrong with the definition
of `average-w/o-extremes`

by using one of the failed inputs, stepping through
the code and repeatedly predicting what should happen next, until one
of your predictions fails to match. Printing the results of intermediate expressions may help.

e. Correct the implementation of `average-w/o-extremes`

.

f. Describe the corrections you made.

a. Familiarize yourself with the documentation for `drop-to-first-zero`

, `remove-below`

, `remove-above`

, and `filter-range`

.

b. Execute `(filter-range numbers 5 15)`

in the interactions pane to verify that it filters out all numbers outside of the range 5 to 15. Does it give you the output you expect?

c. Notice that `filter-range`

duplicated the `lower`

and `upper`

values in the list of numbers. Step through the code using the debugger to identify which procedure is responsible for the error and fix it.

d. Write a few more tests for `filter-range`

using your own lists and bounds and run them.

e. If you did not find any errors, consider the case `(filter-range (list) 15 20)`

. Step through the code using the debugger to identify which procedure is responsible for the error and fix it.

f. Describe what corrections you made (in both part c or part e).

Discuss with your partner each of the following strategies for finding problems in code. Which do you use? In what situations do you find it most helpful?

a. When dealing with a procedure over lists, first try it on the empty list, then on a few singleton lists, then on a few two-element lists, then on a few three-element lists, and so on and so forth.

b. Work out what the code should do on paper.

c. Rewrite the procedure again and compare your old answer to your new answer.

d. Make a list of inputs on which it fails and see if you can identify a common problem, then look to see what in the code relates to that problem.

e. Compare inputs for which it succeeds to inputs for which it fails and see how they differ. Then see where that difference might appear in the code.

Make a list with your partner of other strategies you use when looking for problems in your code.

*We have not yet identified activities for those of you with extra time.
You may depart early, but quietly.*