n1/d1 - n2/d2 = (n1*d2 - n2*d1) / (d1*d2)
n1/d1 * n2/d2 = (n1*n2) / (d1*d2)
(n1/d1) / (n2/d2) = (n1*d2) / (d1*n2)
n1/d1 = n2/d2 iff n1*d2 = n2*d1
Assume that we have a constructor called make-rat, which
takes a numerator and a denominator and returns a rational number
representation. Also assume that we have two selectors,
numer and denom. Both selectors take a rational
number representation. numer returns the numerator of the
rational number and denom returns the denominator of the
rational number.
(define (add-rat x y)
(make-rat (+ (* (numer x) (denom y))
(* (numer y) (denom x)))
(* (denom x) (denom y))))
(define (sub-rat x y)
(make-rat (- (* (numer x) (denom y))
(* (numer y) (denom x)))
(* (denom x) (denom y))))
(define (mul-rat x y)
(make-rat (* (numer x) (numer y))
(* (denom x) (denom y))))
(define (div-rat x y)
(make-rat (* (numer x) (denom y))
(* (denom x) (numer y))))
(define (equal-rat? x y)
(= (* (numer x) (denom y))
(* (numer y) (denom x))))
We could also write sub-rat by writing negate-rat
then using it and add-rat to define sub-rat:
(define (negate-rat x)
(make-rat (- (numer x))
(denom x)))
(define (sub-rat x y)
(add-rat x (negate-rat y)))
How can we write the constructors and selectors? Scheme has a
compound structure called a pair which is constructed with the
primitive procedure cons. cons takes two arguments
and returns a compound data object containing the two arguments as
parts.
(define a (cons 2 3)
We can draw box and pointer diagrams to represent cons cells. A cons
cell is drawn as two connected squares. For the example above, the
first square would have an arrow pointing to the number 2 and the
second box would have an arrow pointing to the number 3. See the book
or the videotaped lecture to see what they look like.
How do we get the elements from a pair? The first box of the cons cell is called the car. We would write (car a), which would return the number 2. The second box of the cons cell is called the cdr. We would write (cdr a), which would return the number 3.
Cons pairs have the property of closure. Anything constructed by cons
can be used as an input element to cons. For example,
(define b (cons 7 8))
(define c (cons b 9))
How can we extract 7 from these pairs? (car b) or (car
(car c)). We can also write (car (car c)) as (caar
c).
How can we get 8 from these pairs? (cdr b) or (cdr (car c)) (which can also be written as (cdar c)).
Finally, how can we get 9? (cdr c)
Now that we know about cons, car and cdr,
let's write make-rat, numer and denom.
(define (make-rat n d)
(cons n d))
(define (numer x)
(car x))
(define (denom x)
(cdr x))
These could also be written as follows:
(define make-rat cons)
(define numer car)
(define denom cdr)
And how can we display a rational number?
(define (print-rat x)
(newline)
(display (numer x))
(display "/")
(display (denom x)))
We're not reducing the rational numbers to the lowest terms. How
could we do this? By changing make-rat:
(define (make-rat n d)
(let ((g (gcd n d)))
(cons (/ n g) (/ d g))))
We could also implement make-rat as a procedure:
(define (make-rat n d)
(lambda (proc) (proc n d)))
(define (numer x)
(x (lambda (a b) a)))
(define (denom x)
(y (lambda (a b) b)))