1

我正在阅读“计算机程序的结构和解释”,并且在做其中一个练习(2.1)时遇到了一些麻烦。我正在以 R5RS 模式在 DrRacket 中编码。

这是我的代码:

(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))))

这是 DrRacket 给我的错误消息:

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)))

我想我搞砸了让我们的语法。但我不知道如何解决它。

4

3 回答 3

4

我在变量声明周围添加了一组额外的括号,哎呀。

另外,由于我使用 c 来定义 n 和 d,所以我必须将 let 更改为 let* 才能使其正常工作

我的固定代码:

(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)))
于 2010-09-08T03:16:58.253 回答
3

正如您的编辑所示,您过早地使用 c 标识符。(这就是为什么在修复额外括号的语法问题后它不起作用的原因。)“let”中的标识符看不到对方。您需要将第二个三个让嵌套在第一个下。

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

我不记得 SICP 何时/是否引入了其他 let 形式,但如果您使用大量嵌套的 let 时遇到困难,您可以使用let*其中每个后续标识符都在所有前面的范围内。也就是说,以下两个定义是等价的:

(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)))))

不幸的是,不同的 let 形式的作用域规则对于初学者来说可能有点多。

于 2010-09-08T13:11:21.917 回答
2

尝试这个:

(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)))
于 2010-09-08T03:14:25.283 回答