Make a version of make-rat that handles positive and negative arguments Given the following task from SICP


  Exercise 2.1
  
  Define a better version
  of make-rat that handles both positive
  and negative arguments. Make-rat
  should normalize the sign so that if
  the rational number is positive, both
  the numerator and denominator are
  positive, and if the rational number
  is negative, only the numerator is
  negative.


And these prerequisite functions:

(define (gcd a b) (if (= b 0) a (gcd b (remainder a b))))

(define (numer a) (car a))
(define (denom a) (cdr a))
(define (print-rat a)
  (newline)
  (display (numer a))
  (display "/")
  (display (denom a)))

(define (add-rat a b)
  (make-rat (+ (* (numer a) (denom b))
               (* (numer b) (denom a)))   
            (* (denom a) (denom b))))
(define (sub-rat a b)
  (make-rat (- (* (numer a) (denom b))
               (* (numer b) (denom a)))

            (* (denom a) (denom b))))
(define (mul-rat a b)
  (make-rat (* (numer a) (numer b))
            (* (denom a) (denom b))))
(define (div-rat a b)
  (make-rat (* (numer a) (denom b))
            (* (numer b) (denom a))))


I wrote this version of (make-rat ... ).  What do you think?

(define (make-rat n d)
  (define (sign n d) (if (&gt; (* n d) 0) + -))
  (let* ((abs-n (abs n)) 
         (abs-d (abs d)) 
         (div (gcd abs-n abs-d)))
    (cons ((sign n d) (/ abs-n div)) 
          (/ abs-d div))))
To normalize a fraction, one needs to do two things:


fix the signs of numerator and denominator; and
reduce them to their lowest terms.


Your implementation does these two things just fine.  However, there is an easier way.  To do (1), simply negate both numerator and denominator if the denominator is negative.  To do (2), divide by the greatest common divisor.

One could combine the two steps above.  Divide the numerator and denominator by the greatest common divisor with its sign fixed to be the same as the denominator's sign.  Implementation follows:

(define (make-rat n d)
  (let
      ((div ((if (&lt; d 0) - +) (abs (gcd n d)))))
    (cons (/ n div) (/ d div))))


If gcd always returns a positive number (which your implementation does not), you may remove the call to abs above.