代码之家  ›  专栏  ›  技术社区  ›  ftl

racket:eval,命名空间附加模块与命名空间要求

  •  3
  • ftl  · 技术社区  · 6 年前

    假设我有一个模块“foo.rkt”,它导出一个结构foo,例如,

    #lang racket (provide foo) (struct foo ())
    

    在另一个模块中,我使用“foo.rkt”,但我也希望将绑定到“struct foo”的绑定与另一个命名空间相关联(出于各种原因,我不使用预置,因此我不能使用namespace require)。

    我想我可以使用名称空间附加模块,如下所示:

    (define ns (make-base-namespace))
    (namespace-attach-module (current-namespace) "foo.rkt" ns)
    (eval '(foo) ns)
    

    但这不起作用,因为命名空间映射符号显示s没有绑定到ns中(如果这是查找绑定的唯一位置)。不过,它在repl中确实有效。为什么?

    1 回复  |  直到 6 年前
        1
  •  5
  •   soegaard    6 年前

    我假设问题是避免在“foo.rkt”中两次实例化模块,因为这会导致两个不兼容的结构定义。

    函数 namespace-attach-module 是拼图的一部分,但它只是附加的 命名空间ns的实例化模块(即名称“foo.rkt”)现在与“foo.rkt”的正确实例化相关联。但是它不能使绑定在ns中可用-这是 namespace-require .

    下面是一个例子:

    文件:“computer.rkt”

    #lang racket
    (provide (struct-out computer))
    (struct computer (name price) #:transparent)
    

    文件:“使用computer.rkt”

    #lang racket
    (require "computer.rkt")                                        ; instatiate "computer.rkt"
    (define ns (make-base-namespace))
    (namespace-attach-module (current-namespace) "computer.rkt" ns) ; ns now knows the same instance
    (define a-computer
      (parameterize ([current-namespace ns])
        (namespace-require "computer.rkt") 
        (eval '(computer "Apple" 2000) ns)))    
    
    (computer-name a-computer)  ; works, since ns used the same instantiation of "computer.rkt"
    

    运行此命令的结果是:

    "Apple"
    

    请注意,删除 命名空间附加模块 行导致错误:

    computer-name: contract violation;
     given value instantiates a different structure type with the same name
      expected: computer?
      given: (computer "Apple" 2000)
    

    因为没有了附件, 命名空间需要 将再次安装“computer.rkt”,导致两个不兼容的结构开始声明。