宏扩展可以(或应该)有副作用吗?例如,这是一个宏,它实际上在编译时抓取网页的内容:
#lang racket
(require (for-syntax net/url))
(require (for-syntax racket/port))
(define-syntax foo
(lambda (syntx)
(datum->syntax #'lex
(port->string
(get-pure-port
(string->url
(car (cdr (syntax->datum syntx)))))))))
然后,我可以做(foo "http://www.pointlesssites.com/")
,它将被替换为"\r\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\r\n\t <and so on>"
这是好习惯吗?我是否保证 Racket 只会运行此代码一次?如果我(display "running...")
在宏中添加一行,它只会打印一次,但我不想从一个例子中概括......
PS - 我问的原因是因为我实际上认为这有时真的很有用。例如,这是一个库,它允许您(在编译时)从 Google API Discovery 服务加载发现文档并自动为其创建包装器。我认为如果库实际上是从网络而不是从本地文件中获取发现文档,那将是非常酷的。
另外,举一个具有不同类型副作用的宏的示例:我曾经构建了一个宏,它将 Racket 的一小部分转换为(eta 扩展的)lambda 演算(当然,它仍然可以在 Racket 中运行)。每当宏完成函数的翻译时,它会将结果存储在字典中,以便以后调用宏可以在自己的翻译中使用该函数定义。