【发布时间】:2012-10-16 09:19:41
【问题描述】:
宏扩展可以(或应该)有副作用吗?例如,这里有一个宏,它实际上是在编译时抓取网页的内容:
#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 - 我问的原因是因为我实际上认为这有时真的很有用。例如this 是一个库,它允许您(在编译时)从 Google API 发现服务加载发现文档并自动为其创建包装器。我认为如果库实际上是从网络而不是从本地文件中获取发现文档,那将是非常酷的。
另外,举一个具有不同副作用的宏的示例:我曾经构建了一个宏,它将 Racket 的一个小子集转换为(eta-expanded)lambda 演算(当然,它仍然可以在球拍)。每当宏完成函数的翻译,它会将结果存储在字典中,以便以后调用宏可以在自己的翻译中使用该函数定义。
【问题讨论】:
-
好的,笨蛋。我刚刚意识到我链接到的文档发现库是在编译时读取文件,这是另一种形式的副作用。这并不一定意味着这是一件好事,但它是在真实的库中完成的,所以......
-
关于什么是“副作用”,我最喜欢你记忆结果的例子。 (与读取本地或远程文件的示例相反。在编译时读取 JSON 发现文档与读取 .RKT 文件并没有太大区别。事实上,我几乎朝着发现文档的方向前进,除了我希望他们按原样工作,而不是需要添加 #lang 行。但它可以这样工作的事实——JSON 发现文档可能是一种“语言”——是一个非常球拍很酷。)
-
我很喜欢。问一个涉及图书馆的问题,该图书馆的作者随便给你留言:)我仍然只是学习 Racket 的所有语言扩展/构建功能,但我学的越多,我就越惊讶。
标签: macros racket side-effects