Это то же самое, что и let
и letrec
. С let
вы не можете ожидать наличия привязки при оценке значений. Это влияет только на создание процедуры / лямбда / замыкания, поскольку все процедуры вызываются в среде, в которой они созданы.
(define (test v)
(list 'default v))
(let ((test (lambda (v)
(if (zero? v)
(list 0)
(cons v (test (- v 1)))))))
(test 5))
; ==> (5 default 4)
(letrec ((test (lambda (v)
(if (zero? v)
(list 0)
(cons v (test (- v 1)))))))
(test 5))
; ==> (5 4 3 2 1 0)
Так что в примере let
локальный let
не находится в теле замыкание, потому что оно не существует, когда значения оцениваются. На практике, если вы расширите let
до его эквивалентной лямбда-формы, вы поймете, почему он вызывает глобальный test
:
((lambda (test) (test 5))
(lambda (v)
(if (zero? v)
(list 0)
(cons v (test (- v 1))))))
Вы понимаете, почему он не вызывает сам себя? letrec
специально предназначен для создания локальных процедур, которые сами по себе являются обязательными для решения этой небольшой проблемы. Для правил синтаксиса он имеет те же свойства привязки для похожих имен, но мы имеем дело с синтаксисом, поэтому нам нужно, чтобы шаги не полагались на арифметику времени выполнения c:
(define-syntax stest
(syntax-rules ()
((_ v . rest) '(default v))))
(let-syntax ((stest (syntax-rules ()
((_ v . rest) (cons 'v (stest . rest)))
((_) '()))))
(stest 5 4 3 2 1 0))
; ==> (5 default 4)
(letrec-syntax ((stest (syntax-rules ()
((_ v . rest) (cons 'v (stest . rest)))
((_) '()))))
(stest 5 4 3 2 1 0))
; ==> (5 4 3 2 1 0)
Снова letrec-syntax
гарантирует, что stest
доступен в среде трансформера syntax-rules
, чтобы он соответствовал самому себе вместо макроса верхнего уровня.
Что касается ваших примеров, они не являются Схемой. Возможно, они будут работать в какой-то конкретной реализации схемы c в качестве дополнительной функциональности по умолчанию, но они не будут работать ни в одной реализации R5RS, R6RS или R7RS, как в моих примерах. R6RS имеет syntax-case
в качестве дополнительного трансформатора, и я предполагаю, что R7RS-large также будет иметь дополнительные трансформаторы. Если вы придерживаетесь поведения defacto, вам нужно пометить реализацию c.