Racket:eval、namespace-attach-module 与 namespace-require

Racket: eval, namespace-attach-module vs. namespace-require

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

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

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

我认为我可以按如下方式使用命名空间附加模块:

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

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

我假设问题是避免在 "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)

文件:"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"

运行的结果是:

"Apple"

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

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

由于没有附件,namespace-require 将再次实例化 "computer.rkt",导致开始声明两个不兼容的结构。