我想保留一个特定模块所需模块的列表(让我们说当前模块)。
我觉得还有其他一些选项(比如解析模块?)可以尝试,但我开始玩弄阴影(require)的想法,并将所需的项目添加到带有模块的哈希表中 - 名称。问题是我无法弄清楚如何为它编写语法定义。
虽然不起作用,但函数定义等价如下:
(define require-list (make-hash))
(define require
(lambda vals
; add vals to hash-table with key (current-namespace)
(let ([cn (current-namespace)])
(hash-set! require-list cn
(append vals (hash-ref require-list cn))))
(require vals)))
..似乎应修改最后一行调用以调用原始(require)?
正确的版本或指向如何操作,或任何其他方式实现原始目标的高度赞赏。
答案 0 :(得分:2)
简短版本:
您是否尝试过打开模块浏览器?
简短版本:
现有的require
不是一个功能;它是一种语言形式,以宏的形式实现。这是因为编译器需要收集您所做的相同信息,因此必须在编译时知道所需的模块。
正如您所建议的那样,正确的方法是利用现有的解析。如果展开模块然后遍历生成的树,您应该能够找到 你需要的一切。树将非常大,但将包含(很多实例)相对较少的基元,因此编写这种遍历不应该太难。然而,在设置命名空间锚点等方面会有很多小问题,以便首先实现扩展。
关于你最初的想法:你绝对可以创建一个阴影所需的宏。您将要在另一个文件中定义它并在出路时重命名,以便您的宏可以引用原始要求。此外,require
表单有一堆有趣的子表单,并提出一个试图处理所有这些子表单的宏将是棘手的。但是,如果您正在考虑编写宏,那么您已经在考虑80%的解决方案,那么这可能会让您感到烦恼。
最后:有些表单执行动态模块评估,因此您无法确定所有可能需要的模块,尽管您可能会注释这些表单(或者可能会影响动态模块 - 加载功能)在它们发生时看到这些。
此外,值得一提的是,您可以在Racket邮件列表中获得更准确的答案。
答案 1 :(得分:2)
如果您只想获取特定模块的导入列表,可以使用一个名为module->imports
的方便内置程序来执行您想要的操作。它将返回阶段级别和模块导入之间的映射 - 高于0的阶段级别表示在编译时用于宏扩展的导入。
> (require racket/async-channel)
> (module->imports 'racket/async-channel)
'((0
#<module-path-index:(racket/base)>
#<module-path-index:(racket/contract/base)>
#<module-path-index:(racket/contract/combinator)>
#<module-path-index:(racket/generic)>))
请注意,相关模块必须包含在当前命名空间中才能module->imports
正常工作,require
或dynamic-require
都可以使用。
这将检查编译器已知的信息,因此它将查找特定模块的所有静态导入。但是,John Clements提到的关于动态需求的警告仍然适用:那些可以在运行时动态执行,因此module->imports
不会检测到。