球拍:评估,命名空间连接模块与命名空间需求

ftl*_*ftl 3 namespaces eval racket

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

#lang racket (provide foo) (struct foo ())
Run Code Online (Sandbox Code Playgroud)

在另一个模块中,我使用“ foo.rkt”,但我也想将绑定到“ struct foo”关联到另一个名称空间(出于各种原因,我不使用预制,所以我不能使用名称空间要求) 。

我以为我可以按以下方式使用namespace-attach-module:

(define ns (make-base-namespace))
(namespace-attach-module (current-namespace) "foo.rkt" ns)
(eval '(foo) ns)
Run Code Online (Sandbox Code Playgroud)

但这是行不通的,因为命名空间映射符号显示s在ns中没有绑定(如果这是查找绑定的唯一位置)。但是,它确实可以在REPL中使用。为什么?

soe*_*ard 5

我认为问题是避免在“ 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)
Run Code Online (Sandbox Code Playgroud)

文件:“ use-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"
Run Code Online (Sandbox Code Playgroud)

运行此命令的结果是:

"Apple"
Run Code Online (Sandbox Code Playgroud)

请注意,删除该namespace-attach-module行会导致错误:

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

由于没有附件,namespace-require第二次将声明“ computer.rkt”无效,从而导致两个不兼容的结构开始声明。