我正在探索Scheme宏,但我一直无法找到一种编写照应宏的便携方式。
我正在尝试编写each-it
宏,这样代码:
(each-it (list 1 2 3)
(display it))
扩展到:
(for-each (lambda (it)
(display it))
(list 1 2 3))
我已经用syntax-rules
编写了一个宏,但是当我尝试使用它时,这会给我一个关于未定义标识符的错误。
(define-syntax each-it
(syntax-rules ()
((each-it lst body)
(for-each (lambda (it) body)
lst))))
This SO question提及define-syntax-parameter
,这似乎只是Racket。 This blog post给出了一些Scheme代码示例,但代码示例不能在R5RS
模式下在DrRacket中运行(我认为它是方括号?)。
R4RS has an interesting macro appendix但它不存在于R5RS中,我不知道我是否可以依赖它。
我能以完全可移植的方式编写each-it
宏吗?如果没有,用于编写宏的最广泛的宏系统功能是什么?
答案 0 :(得分:4)
这应该是可移植的,至少在R6RS:
(define-syntax each-it
(lambda (x)
(syntax-case x ()
((_ lst body)
(with-syntax ((it (datum->syntax x 'it)))
#'(for-each (lambda (it) body) lst))))))
答案 1 :(得分:3)
是的,您可以以便携方式编写它,假设R6RS足够便携。 (同样不能说R7RS,目前只有syntax-rules
,并且不清楚将包含在大语言中的内容,或何时会发生。)请参阅uselpa,了解如何做到这一点。 / p>
那我为什么要写另一个答案呢?因为实际上这样做是个坏主意。一个不好的想法,不是在一些模糊的学术意义上,对大多数现实世界的代码都无关紧要 - 在某种意义上可能会在以后咬你。我知道“纸张”使它看起来令人生畏,但至少阅读了你见过的另一个SO问题中提到的the paper的前两部分。具体来说,第1.2节显示了您将要运行的问题。然后,第2节展示了如何“正确”地执行它,这使得编写扩展为使用宏的宏变得繁琐。在这一点上,采取“只是保持卫生”是有吸引力的,但在第2节结束时,你会明白为什么这也不起作用。
除非您有语法参数或类似内容,否则IMO的底线是不会这样做。也许唯一的例外(可能是你的情况)是当你想要自己使用宏时,你永远不会将它提供给其他人。