我正在阅读“计算机程序的结构和解释”,我在进行其中一项练习时遇到了一些麻烦(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)))
我想我已经搞砸了让我们的语法。但我不确定如何解决它。
答案 0 :(得分: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)))
答案 1 :(得分: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形式的范围规则对于初学者来说可能有点多。
答案 2 :(得分: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)))