3

在 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 中完成吗?

4

3 回答 3

10

您不能在 Scheme 中定义顶级之外的顶级绑定。(并且 a 内部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将 internalmy-incfmy-decf定义发送到 external define-values,这是真正的顶级定义发生的地方。

于 2013-06-26T23:48:16.530 回答
3

在这种情况下,我会使用 Chris 的解决方案,但如果您增加对 x 的操作数量,这里还有一个本着“让 Lambda”的精神出现的解决方案:

(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)
于 2013-06-27T08:43:41.857 回答
0

不太优雅,但非常简单:定义顶级变量,然后将它们set!setf它们从内部定义为 lambdas let,具体取决于它是 Scheme 还是 CL。

于 2013-06-28T07:05:16.433 回答