通过球拍

时间:2016-06-17 07:42:15

标签: racket

我想保留一个特定模块所需模块的列表(让我们说当前模块)。

我觉得还有其他一些选项(比如解析模块?)可以尝试,但我开始玩弄阴影(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)?

正确的版本或指向如何操作,或任何其他方式实现原始目标的高度赞赏。

2 个答案:

答案 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正常工作,requiredynamic-require都可以使用。

这将检查编译器已知的信息,因此它将查找特定模块的所有静态导入。但是,John Clements提到的关于动态需求的警告仍然适用:那些可以在运行时动态执行,因此module->imports不会检测到。