通过racket中的模块查找所需模块的列表

通过racket中的模块查找所需模块的列表,racket,Racket,我想保留一个特定模块(比如说当前模块)所需模块的列表 我觉得还有其他一些选择,比如解析模块?这是可以尝试的,但我开始考虑隐藏require并将所需项添加到具有模块名的哈希表中。问题是我不知道如何为它编写语法定义 虽然不起作用,但函数定义等效项如下所示: (define require-list (make-hash)) (define require (lambda vals ; add vals to hash-table with key (current-namespace)

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

我觉得还有其他一些选择,比如解析模块?这是可以尝试的,但我开始考虑隐藏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

一个正确的版本或一个指向如何做到这一点的指针,或实现最初目标的任何其他方式,我们都非常赞赏。

简短版本:

你试过打开模块浏览器吗

简短版本:

你需要一个宏来完成这个,而且 这不是一个完整的解决方案 现有需求不是一种功能;它是一种语言形式,作为宏实现。这是因为编译器需要收集与您相同的信息,因此必须在编译时知道所需的模块

正如您所建议的那样,正确的方法肯定是利用现有的解析。如果展开模块,然后遍历生成的树,您应该能够找到 你需要的一切。树将非常大,但将包含相对较少的原语的许多实例,因此编写这种遍历应该不会太困难。然而,为了首先实现扩展,在设置名称空间锚点等过程中会涉及很多麻烦

关于您的原始想法:您完全可以创建阴影所需的宏。您需要在另一个文件中定义它,并在退出时重命名它,以便宏可以引用原始文件。另外,require表单有一系列有趣的子表单,要想得到一个试图处理所有这些子表单的宏将非常棘手。但是,如果您正在考虑编写宏,那么您已经在考虑80%的解决方案,所以这可能不会困扰您

最后:有些表单执行动态模块求值,因此您永远无法确定可能需要的所有模块,尽管您可能会对这些表单进行注释,或者在动态模块加载函数出现时隐藏这些表单以查看它们

此外,值得一提的是,您可能会在Racket邮件列表中获得更精确的答案。

简短版本:

你试过打开模块浏览器吗

简短版本:

你需要一个宏来完成这个,而且 这不是一个完整的解决方案 现有需求不是一种功能;它是一种语言形式,作为宏实现。这是因为编译器需要收集与您相同的信息,因此必须在编译时知道所需的模块

正如您所建议的那样,正确的方法肯定是利用现有的解析。如果展开模块,然后遍历生成的树,您应该能够找到 你需要的一切。树将非常大,但将包含相对较少的原语的许多实例,因此编写这种遍历应该不会太困难。然而,为了首先实现扩展,在设置名称空间锚点等过程中会涉及很多麻烦

关于您的原始想法:您完全可以创建阴影所需的宏。您需要在另一个文件中定义它,并在退出时重命名它,以便宏可以引用原始文件。另外,require表单有一系列有趣的子表单,要想得到一个试图处理所有这些子表单的宏将非常棘手。但是,如果您正在考虑编写宏,那么您已经在考虑80%的解决方案,所以这可能不会困扰您

最后:有些表单执行动态模块求值,因此您永远无法确定可能需要的所有模块,尽管您可能会对这些表单进行注释,或者在动态模块加载函数出现时隐藏这些表单以查看它们


此外,值得一提的是,您可能会在Racket邮件列表中获得更精确的答案。

如果您只想获得特定模块的导入列表,则有一个方便的内置名为的功能,它可以满足您的需要。它将返回阶段级别和模块导入之间的映射。高于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都可以

这将检查编译器已知的信息,因此它将查找特定模块的所有静态导入。然而,关于dyn的警告
John Clements提到的amic要求仍然适用:这些要求可以在运行时动态执行,因此不会被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检测到。

感谢您的提示,John。当我对宏比较熟悉时,我将尝试使用阴影宏,添加到哈希表中,然后调用正常操作的原始require。啊,是的,我也应该尝试使用邮件列表。谢谢你的指点,约翰。当我对宏比较熟悉时,我将尝试使用阴影宏,添加到哈希表中,然后调用正常操作的原始require。啊,是的,我也应该尝试使用邮件列表。这看起来非常令人印象深刻,几乎就是我要找的!就我目前的目的而言,阶段0映射就足够了。我还想知道,如果我在另一个模块的函数中调用这个函数,有没有办法获取调用方的模块名?我现在迷失在引用的名称空间部分。这看起来非常令人印象深刻,几乎就是我要找的!就我目前的目的而言,阶段0映射就足够了。我还想知道,如果我在另一个模块的函数中调用这个函数,有没有办法获取调用方的模块名?我目前在引用的名称空间部分丢失了。