Maximum Points: 100
datatype Point = Pt of real * real; (* The point (x,y) *) datatype BareShape = Circle of Point * real (* Center and radius r, r >= 0 *) | Rectangle of Point * Point (* Opposite corners *) | Group of BareShape list; (* Group, non-empty *)We do not enforce or expect any other invariants besides the stated ones. For example, a rectangle might degenerate to a line or point. Bare shapes are not general enough to represent information like color, area, or bounding boxes with each shape. To allow this kind of additional information, we generalize the above datatype of
BareShape
to be polymorphic.
datatype 'a Shape = Circle of Point * real * 'a (* Center and radius, r >= 0 *) | Rectangle of Point * Point * 'a (* Opposite corners *) | Group of ('a Shape) list * 'a; (* Group, non-empty *)Note that all shapes in a group must be annotated with information of the same type. A shape's bounding box is the smallest rectangle which encloses all points in the shape. The bounding box is always kept in canonical form
(Pt(x1,y1), Pt(x2,y2))
where x1 <=
x2 and y1 <= y2.
Many operations for a drawing program can be implemented more
efficiently if we store the shape's bounding box together with the
shape. We therefore create a new type for bounding boxes, and an
instance of 'a Shape
where each shape has a bounding box,
and possibly other information associated with it.
(* Box(Pt(x1,y1), Pt(x2,y2)) with x1 <= x2 and y1 <= y2 *) datatype Box = Box of Point * Point; type 'a BoxedShape = (Box * 'a) Shape;
val boxShape : 'a Shape -> 'a BoxedShapeMake sure to organize your code into small functions and document each one of them.
val pointInShape : Point -> 'a BoxedShape -> boolwhich returns true if the point is in the otherwise it returns false. Create a
pointInShape
function which uses bounding box
information to quickly reject shapes which do not apply. Note that the
function (pointInShape p)
may return
true
for several overlapping objects.
Leonardo da Pisa, son of Bonacci, better known as Fibonacci ("Filius Bonaccii") is nowadays well-known mainly to mathematicians and computer scientists for the sequence of numbers that bear his name:
f0 = 1 |
f1 = 1 |
fn+2 = fn+1 + fn |
One of his major concerns in life (1180-1250) were however rabbits. In particular, he was interested in knowing how rabbits reproduce and, assuming to start with one male and one female rabbit, how many rabbits he would get after any fixed amount of time. For this purpose, he came up with the following (admittedly approximate) discrete model of rabbit reproduction:
Starting from one couple of young rabbits, the evolution of the rabbit population can be represented by the infinite sequence of Fibonacci trees whose first five elements are as follows:
Couples of young rabbits are represented as empty circles, while adults are pictured as squares. Internal nodes contribute to the tree structure and can serve the purpose, for example, of computing the age of the rabbits.
The n-th element of this sequence, that we will denote as Tn, is a snapshot of the rabbit population at month n.
The following declaration describes the structure of Fibonacci trees
datatype fibTree = Young | Adult | Node of fibTree * fibTreeNote, however, that not every ML value of type
fibTree
has the form Tn.
Write an SML function nextFibTree, of type fibTree -> fibTree, that, given an object of type fibTree, expands its leaves according to Fibonacci's specification of rabbit reproduction, as exemplified in the figure above.
Note that your function should work for any value of type fibTree
,
not just for Tn.
Use nextFibTree to write a function createFibTree of type int -> fibTree that, given a natural number n, generates Tn.
One curious fact about Fibonnaci trees is that for any n, Tn+2 is a binary tree having Tn as its left subtree and Tn+1 as its right subtree. This is illustrated in the picture below.
On the basis of this property and of examples shown in class, devise an efficient implementation of the function createFibTree' performing the same task as the function createFibTree from the previous question. Carefully state and prove its correctness.
Write an SML function countLeaves, of type fibTree ->
int, that returns the total number of leaves of a given tree (which
may not be of the form Tn). Prove that
countLeaves
returns fn when given the
representation of Tn. Notice that this is the number of
rabbit couples in the nth month.
Implement a structure Rational
which matches the
signature RATIONAL
.
Rationals should be stored as a pair of integers. In order to avoid unnecessary overflow, ensure that numerator and denominator have no common factors. Your functions should assume this invariant on their arguments and guarantee it for their results. Make sure to avoid unnecessary work.
All of the function results should be evident from their names (i.e., leq returns true if and only if its first argument is less than or equal to its second argument).
The fraction function should return the tuple of numerator and denominator, in reduced form. In case of a divide by zero, the divide function should raise the Div exception.
signature RATIONAL = sig (* types *) type rational (* constants *) val zero : rational val one : rational (* conversions *) val rational : int * int -> rational val real : rational -> real val fraction : rational -> int * int (* operations *) val plus : rational * rational -> rational val minus : rational * rational -> rational val times : rational * rational -> rational val divide : rational * rational -> rational (* may raise exception Div *) (* relations *) val equal : rational * rational -> bool val leq : rational * rational -> bool end;
/afs/andrew/scs/cs/15-212-X/studentdir/<your andrew id>/ass2