我正在尝试重新编写let*
卫生宏,我把它作为普通的宏,如果可能,我希望将其作为卫生宏。我对这种宏类型没有太多经验。所以我真的很感激帮助。另外,我工作let*
宏的另一个表示不起作用,与卫生宏一样错误。
工作let*
(define-macro let*1
(lambda (assgn . body)
(let ((loop (gensym))
(lst (gensym)))
(let loop ((lst assgn))
(if (null? lst)
`(begin ,@body)
`((lambda (,(caar lst))
,(loop (cdr lst)))
,(cadar lst)))))))
不工作卫生let*
- > 错误:lambda:不是以下标识符:(caar lst)
(define-syntax let*2
(syntax-rules ()
((let*2 (set ...) body ...)
(let loop ((lst '(set ...)))
(if (null? lst)
body ...
((lambda ((caar lst))
(loop (cdr lst)))
(cadar lst) 1))))))
不工作let*
,但也与第二个错误相同。
(define-macro let*3
(lambda (assgn . body)
(let ((loop (gensym))
(lst (gensym)))
`(let ,loop ((,lst assgn))
(if (null? ,lst)
(begin ,@body)
((lambda ((caar ,lst))
(,loop (cdr ,lst)))
(cadar ,lst)))))))
为一些令人困惑的问题道歉,我已经坚持这个问题已经有一段时间了,咖啡因已经不再有用了。
一些测试(我选择符号名称来测试符号捕获(我知道我没有必要)):
(let*1 ((body 10)
(lst (+ body 1)))
(list body lst))
(let*2 ((body 10)
(lst (+ body 1)))
(list body lst))
(let*3 ((body 10)
(lst (+ body 1)))
(list body lst))
编辑:问题得到解答,通过编辑Lief Andersen代码而不使用let添加了解决方案
(define-syntax let*
(syntax-rules ()
((let*2 ([x1 e1][x2 e2] ...)body ...)
((lambda (x1)
(let* ([x2 e2] ...)
body ...))
e1))))
答案 0 :(得分:1)
R6RS,附录B给出了let*
的{{3}}:
(define-syntax let*
(syntax-rules ()
((let* () body1 body2 ...)
(let () body1 body2 ...))
((let* ((name1 expr1) (name2 expr2) ...)
body1 body2 ...)
(let ((name1 expr1))
(let* ((name2 expr2) ...)
body1 body2 ...)))))
答案 1 :(得分:0)
你的第二个是最接近的。可以使用define-syntax-rule
编写一个hygenic setState
宏。 (如果你是在方案的实现而不是球拍中写这个,你也可以组成value
和onSwitch
来获得同样的效果。)
isSelected
如果你真的很迂腐,你可以制作一个hygenic let*
宏:
define-syntax
答案 2 :(得分:0)
谈到let*
我并不认为卫生是一个问题。您希望公开的let
中的名称,并且您不会引入任何其他绑定。
(require compatibility/defmacro)
(define-macro let*1
(lambda (assgn . body)
(let loop ((lst assgn))
(if (null? lst)
`(begin ,@body)
`((lambda (,(caar lst))
,(loop (cdr lst)))
,(cadar lst))))))
(expand-once
#'(let*1
((a 1) (b 2) (c 3))
(list a b c)))
; ==> #'((lambda (a)
; ((lambda (b)
; ((lambda (c)
; (begin
; (list a b c)))
; 3))
; 2))
; 1)
对我来说似乎没问题。现在,您可以使用syntax-rules
执行相同的操作。此方法不使用方案语言,因此您尝试(caar lst)
假设您希望在生成的扩展中 。
(expand-once #'(let*2 ((a 1) (b 2) (c 3)) (list a b c)))
; ==> #'(let loop ((lst '((a 1) (b 2) (c 3))))
; (if (null? lst)
; (list a b c)
; ((lambda ((caar lst))
; (loop (cdr lst)))
; (cadar lst)
; 1)))
请注意您的代码实际上是如何逐字复制到生成的扩展中的。这是因为假定模式中未解构的所有内容都在语法本身的词法范围内。以下是如何做到这一点:
(define-syntax let*2
(syntax-rules ()
;; handle stop condition (no more bindings)
((let*2 () body ...)
(begin body ...))
;; handle one expansion
((let*2 ((name expr) more-bindings ...) body ...)
(let ((name expr))
(let*2 (more-bindings ...)
body ...)))))
(expand-once
#'(let*2
((a 1) (b 2) (c 3))
(list a b c)))
; ==> #'((lambda (a)
; (let*2 ((b 2) (c 3))
; (list a b c))) 1)
expand-once
只执行一个级别,但通过使用宏扩展器,您将看到它继续,直到所有部分都展开。
那你什么时候需要卫生?在宏中引入绑定时。标准示例通常是swap!
,它交换两个绑定的值:
(define-syntax swap!
(syntax-rules ()
((swap! var1 var2)
(let ((tmp var1))
(set! var1 var2)
(set! var2 tmp)))))
使用syntax-rules
每个绑定而不是模式虽然是在宏的词法范围内,并且eveything不是在每次扩展时创建的新绑定。因此,我可以安全地做到这一点:
(let ((tmp 1) (another 2))
(swap! tmp another)
(list tmp another))
; ==> (2 1)
旧式,你需要这个:
(define-macro swap!
(lambda (var1 var2)
(let ((tmp (gensym "tmp")))
`(let ((,tmp ,var1))
(set! ,var1 ,var2)
(set! ,var2 ,tmp)))))
这适用于上面的示例,但如果我这样做:
(let ((set! 1) (let 2))
(swap! set! let)
(list set! let))
语法规则一将评估为(2 1)
,而define-macro
一个人不会工作。