文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
2.2 用宏实现 Self
在我们的 OBJECT 宏中使用上述模式:
(defmac (OBJECT ([field fname init] ...)
([method mname args body] ...))
#:keywords field method
(letrec ([self
(let ([fname init] ...)
(let ([methods (list (cons 'mname (λ args body)) ...)])
(λ (msg . vals)
(apply (cdr (assoc msg methods)) vals))))])
self))
(defmac (-> o m arg ...)
(o 'm arg ...))
用一些点对象试试:
(define (make-point init-x)
(OBJECT
([field x init-x])
([method x? () x]
[method x! (nx) (set! x nx)]
[method greater (other-point)
(if (> (-> other-point x?) x)
other-point
self)])))
> (let ([p1 (make-point 5)]
[p2 (make-point 2)])
(-> p1 greater p2))
self: undefined;
cannot reference undefined identifier
什么??我们明明用 letrec 定义了 self,为什么报错说它没有定义呢?原因是—— 卫生 !要知道 Scheme 的 syntax-rules 是卫生的,因此,它会透明地重命名宏引入的所有标识符,以确保在宏展开后他们不会意外绑定或者被绑定。使用 DrRacket 的宏步进器(macro stepper)可以很清楚地观察到这一点。你会看到,greater 方法中的 self 标识符与 letrec 表达式中的同名标识符的颜色不同。
幸运的是,defmac 支持一种方法,指定宏本身引入的标识符也可以被用户代码使用。这里我们唯一需要做的是指定 self 就是这样的标识符:
(defmac (OBJECT ([field fname init] ...)
([method mname args body] ...))
#:keywords field method
#:captures self
(letrec ([self
(let ([fname init] ...)
(let ([methods (list (cons 'mname (λ args body)) ...)])
(λ (msg . vals)
(apply (cdr (assoc msg methods)) vals))))])
self))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论