2013-06-26 1 views
3

В Common Lisp я могу оценить следующий фрагмент кода (в SBCL) без сигнализации любой синтаксической ошибки:Различия между Common Lisp и Scheme лексические закупорки

(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 

Когда я пытаюсь оценить соответствующую схему фрагмент код (в 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)))) 

Кто-нибудь знает причину, по которой это невозможно сделать на Схеме?

+1

Вам нужно будет изучить синтаксическое определение LET в DrRacket. Пример Common Lisp действителен, но я бы не использовал его в своем коде. –

+0

@Reiner Joswig Почему бы вам не использовать его в своем коде? –

+1

Вместо этого я бы использовал CLOS. Использование выше упрощает отладку и предотвращает распознавание формы DEFUN в качестве определения функции компилятором. Внутри LET DEFUN больше не является формой верхнего уровня. –

ответ

10

Вы не можете определить привязки верхнего уровня за пределами верхнего уровня, в Схеме. (И внутри 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

Как учитель, который я сказал мне однажды: «Схема - современный Лисп». –

+1

+1 за лучший способ до сих пор :) – Khaledvic

3

решение Криса является то, что я хотел бы использовать в этом случае, но вот еще один в духе „Пусть над 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) 
0

Менее элегантно, но очень просто: определите переменные верхнего уровня, затем set! или setf их в lambdas изнутри let, в зависимости от того, является ли это схемой или CL.