let
它与和相同letrec
。在let
评估值时,您不能期望绑定存在。这只会影响过程/lambda/闭包的创建,因为所有过程都是在创建它们的环境中调用的。
(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
为等效的 lambda 形式,您就会明白它为什么调用 global test
:
((lambda (test) (test 5))
(lambda (v)
(if (zero? v)
(list 0)
(cons v (test (- v 1))))))
你明白为什么它不调用自己吗?letrec
专门用于创建具有自身约束力的本地程序来解决这个小问题。对于语法规则,它对相似名称具有相同的绑定属性,但是我们正在处理语法,因此我们需要使这些步骤不依赖于运行时算术:
(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
以便它匹配自身而不是顶级宏。
至于您的示例,它们不是Scheme。它们可能会在某些特定的方案实现中作为事实上的额外功能工作,但它们不会像我的示例那样在任何 R5RS、R6RS 或 R7RS 实现中工作。R6RS 有syntax-case
一个额外的变压器,我猜 R7RS-large 也会有额外的变压器。如果您追求事实上的行为,则需要标记特定的实现。