handout #14

CS341—Programming Languages

Programming Assignment #6 (Scheme)

due 11 pm Wednesday, 2/21/07

This assignment is meant to bring you up to speed in Scheme and to give you practice with a structure definition.  Several of your procedures will act on something known as a relation.  This concept is important in many branches of computer science, particularly in databases.  Any given relation will be over a particular set of values that we refer to as the domain of the relation.  The relation itself is simply a set of ordered pairs of values from the domain.  For example, the domain might be the set of integers {1, 2, 3}.  An example of a relation would be the following set of ordered pairs that correspond to the relation we call “less than”:

{(1, 2), (1, 3), (2, 3)}

The order of the pairs doesn’t matter.  Below is a list of pairs that would correspond to the relation “less than or equal” over the same domain:

{(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)}

We will use a structure definition as a way to describe a relation:

(define-struct relation (domain pairs))

This is described as define-structure in the textbook.  The main thing to realize about this definition is that it expands into several procedures that you can use to access a relation:

·        (make-relation d p) returns a relation with domain d and pairs p (d should be a list of values, p should be a list of pairs of values from d, neither list should have any duplicates, each pair is represented as a list of two values)

·        (relation? x) returns #t if x is a relation, #f otherwise

·        (relation-domain r) returns the domain of relation r

·        (relation-pairs r) returns the pairs of relation r

For example, we could define the relations described above by saying:

(define less-than (make-relation '(1 2 3) '((1 2) (1 3) (2 3)))

(define less-than-or-equal

  (make-relation '(1 2 3) '((1 1) (1 2) (1 3) (2 2) (2 3) (3 3))))

Once the relations are constructed, we can use the procedures relation-domain and relation-pairs to request the different components.

You are allowed to use any Scheme procedures defined in the standard top-level environment.  This includes macros like if, and, or and procedures like member, map, filter.  For those who want to go deeper into the functional style, you may also call procedures like foldl, foldr, andmap, and ormap even though they are not described in the textbook or in the Scheme standard.  These correspond to the ML functions List.foldl, List.foldr, List.all and List.exists.  There is a short description of these procedures in the How to Design Programs text by Felleisen linked under “Scheme resources” (you’ll find them in the index).

There is one constraint, however, that you must abide by.  For this assignment, any helper procedures must be declared as named local procedures.  You will generally use a letrec expression to define such procedures.  The requirement that they be local means that you can’t define helper procedures in the top-level environment.  They have to be defined inside the procedure that uses them.  The requirement that they be named means that you can’t use a lambda without naming it.  Scheme programmers tend not to name a lambda if it is short and we’ll allow you to do that in the next assignment, but the intent is to make you practice using letrec to define local procedures.

You should use equal? for all of your comparisons on items in a relation because we want the code to work for relations on any type of data, not just relations on simple integers, although you should use = if you know that what you are comparing are simple numbers.  Several of the procedures you are asked to write have a precondition about the type of value passed to the procedure.  You should document these preconditions.  If you want to, you can include code to check for errors and call the procedure error (described in the textbook) if a precondition is violated.

1.      (5 points) Define a procedure collapse that takes a list of numbers and that collapses successive pairs of numbers by replacing the pair with the sum of the numbers.  If the list has an odd length, then the last value is not collapsed.  For example:

(collapse '(3.4 2 8 14.7 3 12)) should return (5.4 22.7 15)

(collapse '(13 4 27 9 48)) should return (17 36 48)

2.      (10 points) Define a procedure stretch that takes a list of integers and that doubles its length by replacing each integer with two numbers that add up to the integer.  The two numbers should each be half of the original, but if the original number is odd, then the first number in the new pair should be one higher in absolute value than the second.  You might want to call the procedures quotient and modulo.  For example:

(stretch '(38 4 19 7 -5)) should return (19 19 2 2 10 9 4 3 -3 -2)

3.      (10 points) Define a procedure all-pairs that takes two lists as arguments and that returns a list of all of the ordered pairs that can be formed with one value from the first list and one value from the second list.  The list should be ordered first by the order of values from the first list and within those groups, ordered by the order of values from the second list.  You can assume that the lists contain no duplicates.  For example:

(all-pairs '(1 2 3) '(a b c d)) should return ((1 a) (1 b) (1 c) (1 d) (2 a) (2 b) (2 c) (2 d) (3 a) (3 b) (3 c) (3 d))

4.      (15 points) Define a procedure reflexive? that takes a relation as an argument and that returns #t if it is reflexive and that returns #f otherwise.  A relation is considered reflexive if for every value x in the doman, the pair (x x) is included in the relation.  For the two sample relations, less-than is not reflexive but less-than-or-equal is reflexive.

5.      (15 points) Define a procedure symmetric? that takes a relation as an argument and that returns #t if it is symmetric and that returns #f otherwise.  A relation is considered symmetric if for every pair (x y) in the relation, the pair (y x) is also in the relation.  Neither of the sample relations is symmetric.

6.      (20 points) Define a procedure transitive? that takes a relation as an argument and that returns #t if it is transitive and that returns #f otherwise.  A relation is considered transitive if for every combination of pairs (x y) and (y z) that are in the relation, the pair (x z) is also in the relation.  Both of the sample relations are transitive.

7.      (25 points) Define a procedure reflexive-closure that takes a relation as an argument and that returns the smallest relation containing the original relation that is reflexive.  In other words, the reflexive closure should include any missing pairs that are needed to make the relation reflexive (but no extra pairs other than the ones that are needed to make it reflexive).

Note: Several of these problem statements talk about returning #t, but in Scheme it is considered acceptable to return any value other than #f to indicate true.  You are allowed to use this interpretation for these problem statements.