在Common Lisp中,我可以评估以下代码片段(在SBCL中),而不会发出任何语法错误信号:
(let ((x 0))
(defun my-incf (y)
(setf x (+ x y)))
(defun my-decf (y)
(setf x (- x y))))
MY-DECF
CL-USER> (my-incf 1)
1
CL-USER> (my-incf 1)
2
CL-USER> (my-decf 1)
1
CL-USER> (my-decf 1)
0
当我尝试评估相应的Scheme代码片段时(在DrRacket中):
(let ((x 0))
(define (my-incf y)
(set! x (+ x y)))
(define (my-decf y)
(set! x (- x y))))
它表示语法错误。
begin (possibly implicit): no expression after a sequence of internal definitions in: (begin (define (my-incf y) (set! x (+ x y))) (define (my-decf y) (set! x (- x y))))
有人知道为什么不能在Scheme中做到这一点?
答案 0 :(得分:10)
您无法在Scheme中定义顶级以外的顶级绑定。 (并且let
内部肯定不在顶层 - 你所拥有的是内部定义,而不是导出到顶级。)但是,使用define-values
,你仍然可以做你需要做的事情:
(define-values (my-incf my-decf)
(let ((x 0))
(values (lambda (y)
(set! x (+ x y))
x)
(lambda (y)
(set! x (- x y))
x))))
但是,您仍然可以使用内部定义,以使您的代码更具可读性:
(define-values (my-incf my-decf)
(let ((x 0))
(define (my-incf y)
(set! x (+ x y))
x)
(define (my-decf y)
(set! x (- x y))
x)
(values my-incf my-decf)))
两全其美。 :-)在这种情况下,values
将内部my-incf
和my-decf
定义发送到外部define-values
,这是真正的顶级定义发生的位置。
答案 1 :(得分:3)
克里斯的解决方案就是我在这种情况下会使用的解决方案,但是这是另一个本着“让兰都达”的精神,如果你增加x上的操作次数就可以派上用场:
(define inc-dec
(let ((x 0))
(lambda (msg y)
(case msg
((incf) (set! x (+ x y)))
((decf) (set! x (- x y)))
(else (error "wot?")))
x)))
(inc-dec 'incf 1)
(inc-dec 'incf 1)
(inc-dec 'decf 1)
(inc-dec 'decf 1)
答案 2 :(得分:0)
不太优雅,但非常简单:根据它是Scheme还是CL,定义顶级变量,然后set!
或setf
将它们定义为let
内的lambdas。