2014-09-13 36 views
3

我正在探索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,这似乎是唯一的球拍。 This blog post给出了一些Scheme代码示例,但代码示例不在R5RS模式下的DrRacket中运行(我认为它是方括号?)。

R4RS has an interesting macro appendix但它不存在于R5RS中,我不知道我是否可以依赖它。

我可以用完全便携的方式编写我的each-it宏吗?如果不是,写宏的最常用的宏系统功能是什么?

+0

R5RS http://people.csail.mit.edu/jaffer/r5rs_6.html#SEC39 – Rptx 2014-09-13 17:34:22

+0

@Rptx中有一段宏,但我看不到任何设备在该部分破坏卫生。 – 2014-09-13 22:16:10

+0

简单的解决办法就是[保持卫生](http://community.schemewiki.org/?anaphoric-if)。 – Sylwester 2014-09-14 00:34:35

回答

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)))))) 
3

是的,你可以把它写在便携方式假设R6RS是对你不够便携。 (在R7RS上也是如此,目前只有syntax-rules,但不清楚大型语言中包含什么,或者何时会发生。)请参阅uselpa's来了解如何做到这一点。

那么我为什么要写另一个答案?因为实际上这样做会是一个糟糕的主意。一个不好的主意不是在某种模糊的学术意义上,对于大多数现实世界的代码来说都没有关系 - 从某种意义上讲,这很可能会在以后出现。我知道“纸”使它看起来很吓人,但至少读了你见过的另一个SO问题中提到的the paper的前两部分。具体来说,第1.2部分显示了您将遇到的问题。然后,第2部分展示了如何“正确地”完成此操作,以便编写可扩展到使用宏的宏。在这一点上,采取“保持卫生”的方式会很有吸引力,但在第二部分结束时,你会明白为什么这样做不起作用。

IMO的底线是,除非你有语法参数或类似的东西,否则就不要这样做。也许唯一的例外(可能是你的情况)是当宏是你打算使用自己的东西时,你永远不会把它提供给其他人。

+0

谢谢,这篇论文是对Scheme中卫生学的一个梦幻般的概述。 – 2014-09-14 12:24:32