Syntax 访问、实例化和声明模块之间有什么区别?

Syntax 访问、实例化和声明模块之间有什么区别?,syntax,module,macros,racket,Syntax,Module,Macros,Racket,racket中的函数,如和,希望声明它们的模块,但不一定要访问或实例化 现在,对于如何需要模块,似乎有几个选项,包括访问和实例化 这让我想知道,声明一个模块、访问一个模块和实例化一个模块之间有什么区别?声明一个模块只是因为这个模块位于当前名称空间的某个地方。这既可以通过一个require来完成,也可以直接用代码写出模块 模块访问和实例化更难理解,最好这样描述: 模块访问正在运行阶段级别1(宏/编译时代码),而不是运行阶段级别0(运行时代码) 模块实例化正在运行阶段级别0代码,但不是阶段级别1代码

racket中的函数,如和,希望声明它们的模块,但不一定要访问或实例化

现在,对于如何需要模块,似乎有几个选项,包括访问和实例化


这让我想知道,声明一个模块、访问一个模块和实例化一个模块之间有什么区别?

声明一个模块只是因为这个模块位于当前名称空间的某个地方。这既可以通过一个require来完成,也可以直接用代码写出模块

模块访问和实例化更难理解,最好这样描述:

  • 模块访问正在运行阶段级别1(宏/编译时代码),而不是运行阶段级别0(运行时代码)

  • 模块实例化正在运行阶段级别0代码,但不是阶段级别1代码

  • 现在,棘手的一点是,要运行阶段级别0代码,您必须事先运行所有较高级别的阶段代码(如果尚未编译)。但是,如果已访问(并编译)此模块,则不会再次运行阶段1级代码

    这可以通过以下名为
    test.rkt的模块看到:

    #lang racket
    
    (require (for-meta 2 racket/base))
    (displayln "phase 0")
    (begin-for-syntax
      (displayln "phase 1")
      (begin-for-syntax
        (displayln "phase 2")))
    
    #lang racket
    (dynamic-require "test.rkt" #f)
    
    此模块具有在阶段0、阶段1和阶段2(宏扩展阶段的宏扩展)运行的代码。在这些阶段中的每一个阶段,它都打印出一行,以指示该阶段正在运行。使用这个模块,我们可以看到模块何时被实例化

    现在,让我们创建以下文件来实例化
    test.rkt

    #lang racket
    
    (require (for-meta 2 racket/base))
    (displayln "phase 0")
    (begin-for-syntax
      (displayln "phase 1")
      (begin-for-syntax
        (displayln "phase 2")))
    
    #lang racket
    (dynamic-require "test.rkt" #f)
    
    如果我们在DrRacket中运行此命令,输出将如下所示:

    phase 2
    phase 1
    phase 0
    
    现在,我们看到
    阶段0
    ,因为模块正在实例化。然而,在本例中,我们还可以看到
    阶段2
    阶段1
    ,因为模块的语法阶段必须实例化以运行
    阶段0
    代码

    但是,如果再次运行它(假设已打开已编译文件的缓存),您将获得:

    phase 0
    
    phase 2
    phase 1
    
    在这种情况下,您只能看到
    阶段0
    ,因为
    阶段1
    和更高的代码已经展开。我们还可以为类似结果的动态需求提供
    0

    现在,如果我们没有将
    0
    #f
    传递到
    动态要求
    ,而是传递了
    (void)
    ,提供了以下文件:

    #lang racket
    (dynamic-require "test.rkt" (void))
    
    然后输出将是(同样,假设已启用编译缓存),如下所示:

    phase 1
    
    这是因为宏级别(阶段1)代码在此处运行,而不是运行时(阶段0)代码。虽然如果我们对test.rkt做一点小小的更改并再次保存它(使缓存无效),我们将得到:

    phase 0
    
    phase 2
    phase 1
    
    这是因为Racket必须扩展
    阶段2
    代码才能运行
    阶段1
    代码。现在,已编译的模块缓存已更新,如果再次运行,它将仅输出:

    phase 1
    
    最后,没有任何方法可以直接使用
    dynamic require
    来保证运行高于阶段级别1的代码(据我所知,如果我错了,请更新)