Scheme中的letrec-syntax和let-syntax有什么区别?
What is the difference between letrec-syntax and let-syntax in Scheme?
有类似的问题,但语法宏没有,我认为不同之处在于一个宏不能像 letrec 和 let 那样看到另一个宏。
但这与 letrec-syntax 和 let-syntax 的工作原理相同
(let-syntax ((foo (lambda (x) `(bar (list ',(car x) ',(caadr x)))))
(bar (lambda (x) `(display ',x))))
(foo (list 1 2 3)))
您能否展示这两个 macros/syntax 不同的代码示例?
编辑:
找到这个:
(let-syntax ((bar (lambda (x) `(display ',x)))
(foo (lambda (x) (bar x))))
(foo (list 1 2 3)))
不适用于 let-syntax
但它适用于 letrec-syntax
,但这样做有什么好处?如果那些局部变量不能是函数(输出是(bar x)
),那么let-syntax
的目的是什么?我需要一个例子,它可以在代码中使用,你不需要 letrec-syntax
并且有 let-syntax
.
就足够了
与let
、letrec
相同。使用 let
您不能期望在计算值时存在绑定。这只会影响 procedure/lambda/closure 创建,因为所有过程都是在创建它们的环境中调用的。
(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 形式,您就会明白为什么它调用全局 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 也会有额外的变压器。如果您追求的是实际行为,则需要标记特定的实现。
有类似的问题,但语法宏没有,我认为不同之处在于一个宏不能像 letrec 和 let 那样看到另一个宏。
但这与 letrec-syntax 和 let-syntax 的工作原理相同
(let-syntax ((foo (lambda (x) `(bar (list ',(car x) ',(caadr x)))))
(bar (lambda (x) `(display ',x))))
(foo (list 1 2 3)))
您能否展示这两个 macros/syntax 不同的代码示例?
编辑:
找到这个:
(let-syntax ((bar (lambda (x) `(display ',x)))
(foo (lambda (x) (bar x))))
(foo (list 1 2 3)))
不适用于 let-syntax
但它适用于 letrec-syntax
,但这样做有什么好处?如果那些局部变量不能是函数(输出是(bar x)
),那么let-syntax
的目的是什么?我需要一个例子,它可以在代码中使用,你不需要 letrec-syntax
并且有 let-syntax
.
与let
、letrec
相同。使用 let
您不能期望在计算值时存在绑定。这只会影响 procedure/lambda/closure 创建,因为所有过程都是在创建它们的环境中调用的。
(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 形式,您就会明白为什么它调用全局 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 也会有额外的变压器。如果您追求的是实际行为,则需要标记特定的实现。