Macros 关于球拍宏的两个问题
关于卫生宏观 我不完全理解宏是如何工作的。这里有两个例子。Macros 关于球拍宏的两个问题,macros,scheme,racket,Macros,Scheme,Racket,关于卫生宏观 我不完全理解宏是如何工作的。这里有两个例子。 第一个是: 这个很好,但是这个: #lang racket (define-syntax (g stx) (syntax-case stx () ([_ arg] #'(display arg)))) (define display 1) (g 3) 将引发异常。如何解释这两种情况之间的区别 如何定义这样的宏 我想定义一个宏来允许racket中的匿名递
第一个是: 这个很好,但是这个:
#lang racket
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(define display 1)
(g 3)
将引发异常。如何解释这两种情况之间的区别
如何实现这一点?为了回答您的第一个问题,您在这里忘记的是,当您这样定义一个模块级别的
时,该定义将适用于整个模块。因此,理论上,您可以这样编写第二个代码块:
#lang racket
(let ([display 1])
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(g 3))
现在可以理解为什么会出现错误,因为宏中的显示绑定到1
,这不是函数
长话短说,把卫生看作是词汇范围。定义宏时,display
绑定到的内容就是它的内容。(这与其他语言中的宏相反,在其他语言中,无论调用(或真正展开)宏时显示的是什么,它都将是什么
现在,为了回答你的第二个问题,我很抱歉,但我不清楚你想问什么。如果你能把它弄清楚一点,那么我可以填写答案的这一部分。为了回答你的第一个问题,你在这里忘记的是,当你这样做一个模块级的定义
时,这个定义对整个过程都是有约束力的所以,理论上,你可以这样写你的第二个代码块:
#lang racket
(let ([display 1])
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(g 3))
现在可以理解为什么会出现错误,因为宏中的显示绑定到1
,这不是函数
长话短说,将卫生视为词汇范围。定义宏时,无论display
绑定到什么,它都将是什么。(这与其他语言中的宏相反,在其他语言中,调用(或真正扩展)宏时,无论display
绑定到什么,它都将是什么
现在,为了回答你的第二个问题,我很抱歉,但我不清楚你想问什么。如果你能把它整理一下,那么我可以填写答案的这一部分。那么你想打破hygene?你需要获得recur
以获得原始表单的词汇上下文,这样recur
就会被视为相同标识符。您可以使用datum->syntax
执行此操作,结果可能如下所示:
#lang racket
(let ([display 1])
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(g 3))
(定义语法(递归-λstx)
(语法大小写stx()
[(args body…)
(使用语法([recur stx(基准->语法stx'recur)])
#'(Z(λ)(重复stx)
(λargs体…)]
现在,只要您的args或body中的嵌套引入recur
,它就会工作:
;多参数递归
(定义Z)
(λ(f)
((λ(g)(g))
(λ(g)
(f(λargs(应用(g)args()()())))
埃克曼
((重现-λ(mn)
(续)
(=m0)(+n1))
(=n0)(重现(-m1)1))
(其他(重复(-m1)(重复-n1(()())))
3.
6)
; ==> 509
如果将recur
设为参数,则此选项无效:
((重现-λ(重现)(重现1))1)
错误:重复不是一个过程
当然,如果进行嵌套绑定:
((重现-λ(a)
(定义重复a)
(重复1次)
1)
错误:重复不是一个过程
当然,您可以单步通过宏扩展器,它会向您显示它的功能如下:
#lang racket
(let ([display 1])
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(g 3))
(展开一次
#'(递归-λ(mn)
(续)
(=m0)(+n1))
(=n0)(重现(-m1)1))
(其他(重现(-m1)(重现-n1(()())))
; ==>
"#"(Z)
;(λ(重复)
;(λ(mn)
(续)
;(=m0)(+n1))
;(=n0)(重复(-m1)1))
(否则)(重复(-m1)(重复-n1(()()()))
那么你想打破hygene吗?你需要获得recur
以获得原始表单的词汇上下文,这样recur
将被视为相同的标识符。你可以使用数据->语法执行此操作,结果可能如下所示:
#lang racket
(let ([display 1])
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(g 3))
(定义语法(递归-λstx)
(语法大小写stx()
[(args body…)
(使用语法([recur stx(基准->语法stx'recur)])
#'(Z(λ)(重复stx)
(λargs体…)]
现在,只要您的args或body中的嵌套引入recur
,它就会工作:
;多参数递归
(定义Z)
(λ(f)
((λ(g)(g))
(λ(g)
(f(λargs(应用(g)args()()())))
埃克曼
((重现-λ(mn)
(续)
(=m0)(+n1))
(=n0)(重现(-m1)1))
(其他(重复(-m1)(重复-n1(()())))
3.
6)
; ==> 509
如果将recur
设为参数,则此选项无效:
((重现-λ(重现)(重现1))1)
错误:重复不是一个过程
当然,如果进行嵌套绑定:
((重现-λ(a)
(定义重复a)
(重复1次)
1)
错误:重复不是一个过程
当然,您可以单步通过宏扩展器,它会向您显示它的功能如下:
#lang racket
(let ([display 1])
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(g 3))
(展开一次
#'(递归-λ(mn)
(续)
(=m0)(+n1))
(=n0)(重现(-m1)1))
(其他(重现(-m1)(重现-n1(()())))
; ==>
"#"(Z)
;(λ(重复)
;(λ(mn)
(续)
;(=m0)(+n1))
;(=n0)(重复(-m1)1))
(否则)(重复(-m1)(重复-n1(()()()))
如果将这个问题分为两个独立的问题,每个问题都独立提出会更好。如果将这个问题分为两个独立的问题,每个问题都独立提出会更好。谢谢你的回答,这很有帮助。正如Sylvester所说,我真正想做的是在第二个问题中打破hygenen、 谢谢你的回答,谢谢