tags:

views:

132

answers:

3

I'm going through "Structure and Interpretation of Computer Programs" and I'm having a bit of trouble doing one of the exercises ( 2.1 ) . I'm coding in DrRacket in R5RS mode.

here's my code :

(define (make-rat n d) 
  (let (((c (gcd n d))
         (neg (< (* n d) 0))
         (n (/ (abs n) c))
         (d (/ (abs d) c)))
        (cons (if neg (- n) n) d))))

and here's the error message DrRacket is giving me:

let: bad syntax (not an identifier and expression for a binding) in: ((c (gcd n d)) (neg (< (* n d) 0)) (pn (/ (abs n) c)) (pd (/ (abs d) c)))

I think I've messed up let's syntax. but I'm not sure how to fix it.

+1  A: 

Try this:

(define (make-rat n d)
  (let ([c (gcd n d)]
        [neg (< (* n d) 0)]
        [n (/ (abs n) c)]
        [d (/ (abs d) c)])
    (cons (if neg
              (- n)
              n) 
          d)))
zakovyrya
how are the brackets different from parentheses?
Bwmat
They are not. Just better visually.
zakovyrya
@Bwmat: Brackets aren't different from parentheses in Racket. It's just easier to see the distinction between different lists when levels of nesting use different characters. The convention seems to be that "syntactic" lists (like the bindings in `let`-forms) are often given square brackets.
Chuck
Yeah, it does look cleaner, thanks for the tip
Bwmat
actually, it doesn't seem to work in DrRacket
Bwmat
It won't work in DrRacket if you're using the R5RS mode -- which is *not* a good idea...
Eli Barzilay
@Eli Barzilay: is there a better mode in DrRacket with respect to SICP?
Bwmat
@Bwmat: Yes, this is much better -- http://www.neilvandyke.org/sicp-plt/
Eli Barzilay
+4  A: 

I added an extra set of parentheses around the variable declarations, whoops.

Also, since I used c to define n and d, I had to change let into let* to make it work properly

my fixed code:

(define (make-rat n d) 
  (let* ((c (gcd n d))
         (neg (< (* n d) 0))
         (n (/ (abs n) c))
         (d (/ (abs d) c)))
        (cons (if neg (- n) n) d)))
Bwmat
+2  A: 

As your edit indicates, you're using the c identifier prematurely. (Which is why it isn't working after fixing the syntax issue of the extra parenthesis.) Identifiers in "let" don't see each other. You'd need to nest your second three lets under the first.

    (let ((c (gcd ...)))
      (let ((...))
        exps ...))

I don't recall when/if SICP introduces other let forms, but if you are stuck using a lot of nested lets, you can use let* in which each subsequent identifier is in the scope of all the previous. That is, the following two definitions are equivalent:

(define foo
  (let* ((a 1)
         (b (+ 1 a))
         (c (+ 1 b)))
    (+ 1 c)))

(define foo
  (let ((a 1))
    (let ((b (+ 1 a)))
      (let ((c (+ 1 b)))
        (+ 1 c)))))

The scoping rules of the different let forms can be a bit much for a beginner, unfortunately.

anonymous
Re "scoping rules can be a bit much", I've found that a good mental model to use is to macro-expand the `let` into the respective `lambda` (and `let*` into a sequence of `let`s/`lambda`s). Of course, this won't help beginners much; oh well.
Chris Jester-Young