Answer four of the following six questions. Each question is worth 25 points. While the problems have equal value, they are not of equal difficulty. Some will take you longer, some will take you less time.

**1. Testing Scheme Routines**

*
Suppose you've been hired to test a Scheme function which is documented as
follows:
*

;;; (positionOf val lst) ;;; Given a number,val, and a sorted list of numbers, ;;;lst, determine the position ofvalinlst. ;;; If the value is in the list, returns the position of the ;;; first appearance of the value. ;;; If the value is not in the list, returns 0. ;;; Preconditions: ;;; The list must be sorted in increasing order. ;;; All elements of the list must be numbers. ;;; The value must be a number. ;;; Postconditions: ;;; The appropriate position is returned (as described above). ;;; The list is not modified. ;;; Examples: ;;; (positionOf 1 '(1 5 11)) => 1 ;;; (positionOf 2 '(1 1 2 3)) => 3 ;;; (positionOf 3 '(2 3 3 3) => 2 ;;; (positionOf 2 '(1 5 11)) => 0 ;;; (positionOf 1 '()) => 0 ;;; (positionOf 1 '(3 2 1)) =>unspecified, may crash;;; (positionOf 1 '(a 1 b)) =>unspecified, may crash;;; (positionOf 1 '(1 a b)) =>unspecified, may crash

`positionOf`

were
working in good faith. That is, they tried to create a working
function, but may have failed nonetheless because of inadvertent errors.
*
Write a Scheme predicate, testPositionOf?, that performs a
reasonable set of tests on the positionOf function and
returns true if it appears that the function works correctly and false
otherwise. Your predicate should not return true if it is likely that
positionOf fails to work as advertised nor should it return
false if it is likely that positionOf is likely to work
correctly. Your goal is only to check that it correctly identifies the
position of a value. You need not the other postconditions.
*

*
You may rely on the existence of "reasonable" helper functions (such as
nints). Just make sure to document clearly what you expect
the helper functions to do.
*

*
Since you are working under time pressure, I will not expect a perfectly
thorough or working answer, simply a reasonable one.
*

Everyone who took CS223 (which should be most of you) should have known
this answer, since it's a key part of a chapter of Bentley that we
discussed (remember that chapter on binary search, testing binary search,
and loop invariants). However, few of you seemed to recall it. Those
who didn't recall it should still have been able to model their tests
on the one from assignment
five. In particular, *it is important to test different size
lists*. In addition, *it is important to test the case that the
element isn't in the list as well as the case that it is in the list*.
For "not in the list", you should not just check "smaller than the front"
and "larger than the back".

For these purposes, it seems sufficient to test list sizes from 0 to some reasonable number (perhaps 8, perhaps sixteen) and to test a search for each position in the list and between each two positions in the list (as well as before the beginning and after the end).

To make it easy to check whether the search is successful, I'll build a somewhat regular list. In particular, I'll build a list of even integers starting with two. That way, an even number is at position N/2 and odd numbers aren't in the list. To handle the different length lists, I'll use a helper function. The disadvantage of this solution is that it fails for a function that simply returns N/2 for even numbers and 0 for odd numbers. However, we could use a couple of variants to handle such cases. Since we're assuming that the people who gave us the function are working in good faith, such cases may not be necessary.

First, a helper function that checks whether the function returns the correct position when looking for a value in the list.

;;; Check if a positionOf function finds the correct position of ;;; a number in a list of even numbers starting with two. If the ;;; number is odd, it shouldn't be in the list. If the number is ;;; even and the length of the list is less than or equal to N/2, ;;; then it should be at position N/2. (define (testParticularPosition fun num lst) (if (odd? num) (equal? 0 (fun num lst)) (equal? (/ num 2) (fun num lst))))

Next, a helper function that checks every position in the list.

;;; Check if a positionOf function finds the correct position of ;;; every number between 1 and 2N+1 in the list (2 ... 2N). (define (testAllPositions fun N) (let ((lst (evens N))) (myand (map (lambda (num) (testParticularPosition fun num lst)) (nints (+ (* 2 N) 1) 1)))))

Finally, our test function. It checks a variety of sizes of lists. Note
that we use `map`

on a list of integers to test the different
size lists and then we use "and" the results together.

;;; Check if a positionOf function finds the correct position of ;;; every number between 1 and 2N+1 in every list size between ;;; 0 and 16. (define (testPositionOf? fun) (myand (map (lambda (len) (testAllPositions fun len)) (nints 17 0))))

In order for this to work correctly, we need the following functions defined.

;;; (nints n start): ;;; create the list of n consecutive integers starting with start ;;; (evens n): ;;; create the list of n consecutive even numbers starting with 2 ;;; (myand lst): ;;; "and" all the elements of a list of booleans

The definitions of all three are relatively straightforward.

;;; Create a list of n consecutive integers starting with start (define (nints n start) (if (= n 0) nil (cons start (nints (- n 1) (+ start 1))))) ;;; Create a list of n consecutive even integers starting with 2. ;;; If n is odd, creates a list of n consecutive odd integers. (define (evens n) (letrec ((evens-from (lambda (n start) (if (= n 0) nil (cons start (evens-from (- n 1) (+ start 2))))))) (evens-from n 2))) ;;; "And" all the elements of a list of booleans. If the list is ;;; empty, return true (#t). (define (myand lst) (if (null? lst) #t (and (car lst) (myand (cdr lst)

Note that this isn't an ideal solution, as it doesn't check lists with duplicates. We might instead build a list of pairs, such as

Then the appropriate place for each element is the value of the element.(1 1 3 3 5 5 7 7 ...)

For those interested in testing their own solutions, here's a
`positionOf`

function to test. Note that I've used
nested `if`

s when a `cond`

would probably
be somewhat better.

;;; Find the position of a number in a sorted list. Still a linear ;;; time method, but stops when it goes too far. (define (positionOf num lst) ; Base case: empty list. The number can't be there. (if (null? lst) 0 ; Base case: number is at the start of the list. Return 1. (if (= num (car lst)) 1 ; Base case: number is too small. Return 0 (if (< num (car lst)) 0 ; Recursive case: look for the number in the rest of the list (let ((check (positionOf num (cdr lst)))) ; If it's not in the rest of the list, give up (if (= check 0) 0 ; If it is in position X in the rest of the list, it's at ; position X+1 in the whole list (+ check 1)))))))

Here's one to test that has a slight bug.

(define (badPositionOf num lst) ; Base case: empty list. The number can't be there. (if (null? lst) 0 ; Base case: single element list and the number is too small. It ; can't be there. (if (and (null? (cdr lst)) (<= num (car lst))) 0 ; Base case: number is at the start of the list. Return 1. (if (= num (car lst)) 1 ; Base case: number is too small. Return 0 (if (< num (car lst)) 0 ; Recursive case: look for the number in the rest of the list (let ((check (badPositionOf num (cdr lst)))) ; If it's not in the rest of the list, give up (if (= check 0) 0 ; If it is in position X in the rest of the list, it's at ; position X+1 in the whole list (+ check 1))))))))

**2. Removing Copies**

*
Often, it is useful to remove all copies of a value from a list of
values. Scheme includes such a function as one of its basic functions.
Nonetheless, I would like you to write such a function for yourself.
Write a function (removeAllCopies val lst) that returns a
version of lst with all elements equal to val
removed. Note that some or all values in the list may not be numbers.
*

Everyone who did this problem did a fairly good job. Some seemed to
think that they needed to cons nil with the rest of the list in the
"it's at the front" case, but that's clearly wrong. Some used
`=`

instead of `equal?`

, but I didn't consider
that a real problem.

;;; Remove all copies of a value from a list of values. Written ;;; to handle arbitrary kinds of values. (define (removeAllCopies val lst) (if (null? lst) nil (let ((first (car lst)) (rest (removeAllCopies val (cdr lst)))) (if (equal? first val) rest (cons first rest)))))

**3. Triangular Numbers**

*
Without using recursion or loops, write a Haskell function,
triangular that returns the series of triangular numbers,
*

1 3 6 10 15 21 ...

`compose`

,
`head`

,
`intsfrom`

,
`map`

,
`select`

,
`sum`

,
`take`

(Haskell's `firstn`

),
`tail`

,
and other similar functions.
*
Make sure you indicate the type of your function.
*

Many of use missed the fact that `triangular`

produces an
infinite list. In effect, `triangular`

takes no parameters.
Its type is therefore "list of integers" which we represent as
`[Int]`

.

triangular :: [Int]

Since I disallowed recursion, the most reasonable thing to do was to simply map a function that computes the nth triangular number onto the list of integers. Here's that solution. Note that to compute the nth triangular number, you simply sum the numbers from 1 to n.

triangular = map (\n -> sum (take n (intsfrom 1))) (intsfrom 1)

There is also an elegant recursive solution that involves using the previous result (since the nth triangular number is the (n-1)st triangular number + n).

triangular = 1 : (sumpairs triangular (intsfrom 2))

This requires a helper function to add pairs of numbers, one from each list.

sumpairs :: [Int] -> [Int] -> [Int] sumpairs (x:xs) (y:ys) = (x + y) : (sumpairs xs ys)

**4. Binary Trees**

*
Define a general binary tree datatype in Haskell, including appropriate
type constructors. Then write a function that converts binary trees to
lists. That is, your function should take a binary tree as input and
create a list of the elements in the tree. You can choose the traversal
order for the conversion function.
*

Note that an answer to this could be found in the Gentle Introduction to Haskell that I recommended you read. This is a variant.

I've chosen to have leaves that include no values, so the only values are in the interior of the tree. This makes my life a little bit easier.

data BinaryTree a = Leaf | Node a (BinaryTree a) (BinaryTree a)

For traveral, I'll take advantage of recursion and do a depth-first,
preorder, left-to-right traveral. (Many of you neglected to describe
which traversal order you were using.) Note that `++`

is the
Haskell concatenation operator.

treeToList :: (BinaryTree a) -> [a] treeToList Leaf = () treeToList (Node val left right) = [val] ++ (treeToList left) ++ (treeToList right)

**5. Functional Programming in Pascal**

*
In the start of chapter 10, Louden suggests that it's possible to do
"functional" programming in Pascal. However, much of what he calls
"functional" is simply recursive. Could one convince a functional
programmer trained in Scheme or Haskell that Pascal is functional? If
so, how? If not, why not?
*

There are a number of aspects to functional programming. While the
application of functions is certainly important, the use of functions as
"first class values" is also important. While some version of Pascal do
permit the use of functions as parameters to other functions, Pascal
does not permit you to return functions from functions. So, for
example, it would be impossible to write `compose`

in Pascal.

Some of you noted that Pascal relies on side effects for much of its computation. Nonetheless, it is certainly possible to write a Pascal program without side effects (as long as you're willing to do without assignment). In addition, there are many functional languages (Scheme included) that permit side effects.

Pascal also lacks facilities to return structured types, does not include garbage collection or symbolic values, and does not permit lambda abstractions.

Note that p. 365 of Louden contains many similar arguments.

**6. Evaluation and Application**

*
Scheme includes eval and apply functions that
make it possible for programmers to build and evaluate expressions. For
example,
*

> (define exp '(+ 2 3)) > exp(+ 2 3)> (exp)> (eval exp)Error: attempt to apply non-procedure (+ 2 3)5> (define nums '(2 3 1 5)) > nums(2 3 1 5)> (+ nums); remember that + is "sum"> (apply + nums)Error in +: (2 3 1 5) is not a number.11> (define (oddlist a b) (list a b b a)) > (oddlist 'alpha 'beta)(alpha beta beta alpha)> (define ab '(alpha beta)) > (define exp2 '(oddlist ab)) > exp2(oddlist ab)> (eval exp2)> (define exp3 '(apply oddlist ab)) > exp3Error: incorrect number of arguments to #<procedure oddlist>.(apply oddlist ab)> (eval exp3)(alpha beta beta alpha)

*
Haskell appears to include no explicit equivalent to either
eval or apply. This suggest either that such
functions are unnecessary in Haskell or that it would be impossible to
include them in Haskell. Which do you think is the case, and why?
*

Because Haskell is curried, we don't need `apply`

because
simply writing a function and its arguments gives us application (we
need `apply`

in Scheme because we have functions that we
want to apply to multiple parameters). For example, to apply
`fun`

to `val1`

and `val2`

, we could
simply write `fun val1 val2`

. However, if `val1`

and `val2`

are in a list, we need to do something a little
bit more sophisticated (but certainly possible).

It would be difficult if not impossible to write `eval`

because `eval`

cannot be typed. What kind of value does it
return? You can't just say "some type". For example, is ```
(eval
whatever) + 2
```

a legal expression? Similarly, it's not clear what
the argument type for `eval`

is. Presumably, it's something
like `Expression`

, but what are expressions?

Many of you said "Haskell is lazy; neither fits in the context of lazy
evaluation." That is not a clear argument nor does it seem correct.
`eval `

is simply an expression whose result
is the result of evaluating *exp**exp*. If the "eval expression" is
not needed, then the evaluation never needs to be done.

A number of you suggested that the role of lists is quite different
in the two languages and that `eval`

corresponded to Scheme's
notion of list and not Haskells. I would tend to agree with that
assertion.

**Disclaimer** Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.

Source text last modified Wed Apr 29 10:12:05 1998.

This page generated on Wed Apr 29 10:16:54 1998 by SiteWeaver.

Contact our webmaster at rebelsky@math.grin.edu