使用 Racket 实现 SICP 评估器
Implement SICP evaluator using Racket
我正在研究 4.1.4 Running the Evaluator as a Program
的元循环求值器,用 Racket 构建它:
#lang racket
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
(define (evaluate exp)
(cond
; ...
((definition? exp) (display exp)
(display " is a definition\n"))
; ...
(else (display exp)
(display " is something else\n"))))
(define (definition? exp)
(tagged-list? exp 'define))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(define (driver-loop)
(let ((input (read)))
(let ((output (evaluate input)))
output))
(driver-loop))
(driver-loop)
在DrRacket中得到一个成功读取输入的框后,我输入(define a 0)
结果是:
(define a 0) is something else
去掉就可以识别了
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
但没有它我将无法调用 set-car!
或 set-cdr!
。 set-
函数有替代方案吗?
或者我可以选择从 rnrs/base-6
和 rnrs/mutable-pairs-6
导入什么吗?
应该运行 没问题。我用你给的代码做了一个快速测试。
(define (evaluate exp)
(cond
; ...
((definition? exp) (display exp)
(display " is a definition\n"))
; ...
(else (display exp)
(display " is something else\n"))))
(define (definition? exp)
(tagged-list? exp 'define))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(define (driver-loop)
(let ((input (read)))
(let ((output (evaluate input)))
output))
(driver-loop))
(driver-loop)
运行 球拍语言中的这个会给我:
--> is user input
-->(define a 0)
(define a 0) is a definition
-->(list 1 2 3)
(list 1 2 3) is something else
如您所见,已输入条件的右分支。
您确定错误来自 else
分支吗?因为您的错误消息包含 :
,else 分支中的 display
不要。
编辑:您在输入提示中究竟输入了什么?
混淆可能是对 Racket 的 eval
函数的调用需要一个列表作为参数,(eval '(define a 0))
。但是,如果您在输入提示中输入它,它将不起作用。您必须像正常定义一样编写 (define a 0)
。
这是错误:
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
包 rnrs/base-6
和 rnrs/mutable-pairs-6
带来了一些意想不到的变化 cons
(以及 car
、cdr
)导致 (define a 0)
没有被 definition?
抓住
解决方案:
(require (only-in (combine-in rnrs/base-6
rnrs/mutable-pairs-6)
set-car!
set-cdr!))
始终将 only-in
放在 require
中以避免任何不需要的绑定。
我正在研究 4.1.4 Running the Evaluator as a Program
的元循环求值器,用 Racket 构建它:
#lang racket
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
(define (evaluate exp)
(cond
; ...
((definition? exp) (display exp)
(display " is a definition\n"))
; ...
(else (display exp)
(display " is something else\n"))))
(define (definition? exp)
(tagged-list? exp 'define))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(define (driver-loop)
(let ((input (read)))
(let ((output (evaluate input)))
output))
(driver-loop))
(driver-loop)
在DrRacket中得到一个成功读取输入的框后,我输入(define a 0)
结果是:
(define a 0) is something else
去掉就可以识别了
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
但没有它我将无法调用 set-car!
或 set-cdr!
。 set-
函数有替代方案吗?
或者我可以选择从 rnrs/base-6
和 rnrs/mutable-pairs-6
导入什么吗?
应该运行 没问题。我用你给的代码做了一个快速测试。
(define (evaluate exp)
(cond
; ...
((definition? exp) (display exp)
(display " is a definition\n"))
; ...
(else (display exp)
(display " is something else\n"))))
(define (definition? exp)
(tagged-list? exp 'define))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(define (driver-loop)
(let ((input (read)))
(let ((output (evaluate input)))
output))
(driver-loop))
(driver-loop)
运行 球拍语言中的这个会给我:
--> is user input
-->(define a 0)
(define a 0) is a definition
-->(list 1 2 3)
(list 1 2 3) is something else
如您所见,已输入条件的右分支。
您确定错误来自 else
分支吗?因为您的错误消息包含 :
,else 分支中的 display
不要。
编辑:您在输入提示中究竟输入了什么?
混淆可能是对 Racket 的 eval
函数的调用需要一个列表作为参数,(eval '(define a 0))
。但是,如果您在输入提示中输入它,它将不起作用。您必须像正常定义一样编写 (define a 0)
。
这是错误:
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
包 rnrs/base-6
和 rnrs/mutable-pairs-6
带来了一些意想不到的变化 cons
(以及 car
、cdr
)导致 (define a 0)
没有被 definition?
解决方案:
(require (only-in (combine-in rnrs/base-6
rnrs/mutable-pairs-6)
set-car!
set-cdr!))
始终将 only-in
放在 require
中以避免任何不需要的绑定。