Module 如何制作参数化模块

Module 如何制作参数化模块,module,racket,Module,Racket,我知道以“有可能吗”开始问球拍问题有点傻(但我来了) 是否可以创建类似于OCaml的函子的参数化模块? 假设我有以下结构 ;;module A (define x ...) (provide foo) (define (foo a) (format "x for foo: ~a ~a" x a)) (define (bar a) (format "x for bar: ~a ~a" x a)) 然后我定义了另外两个使用模块作为定义的模块 ;;module B (require "A.rk

我知道以“有可能吗”开始问球拍问题有点傻(但我来了)

是否可以创建类似于OCaml的函子的参数化模块? 假设我有以下结构

;;module A
(define x ...)

(provide foo)

(define (foo a) (format "x for foo: ~a ~a" x a))
(define (bar a) (format "x for bar: ~a ~a" x a))
然后我定义了另外两个使用模块作为定义的模块

;;module B

(require "A.rkt" #| '(value for x is "lala") |# )

(define result1 (foo "lulu"))
(define result1 (bar "lili"))

;;result1 => "x for foo: lala lulu"
;;result2 => "x for bar: lala lili"

显然,我可以定义foo和bar,使它们各自有一个附加参数, 部分应用该附加参数并定义新函数

;;module A2

(provide foo)

(define (foo x a) (format "x for foo: ~a ~a" x a))
(define (bar x a) (format "x for bar: ~a ~a" x a))
然后

;;module B2

(require "A2.rkt")

(define foo1 (partial foo "homemade"))
(define bar1 (partial bar "homemade"))

(define result1 (foo1 "really"))
(define result1 (bar1 "nothing"))

;;result1 => "x for foo: homemade really"
;;result2 => "x for bar: homemade nothing"
但这并不是我想要的——相反,我希望以某种方式保留模块/需求方式,而不必重新定义 这些(几乎相同的)功能反复出现


有什么办法吗?

正如Alexis所提到的,与ML函子相对应的最接近的东西是系统。下面是将您的示例(稍微简化)转换为单位的一个例子

首先,为组件之间的接口定义签名:

(define-signature in^ (x))
(define-signature out^ (foo bar))
A
组件接受
in^
绑定的值(此处仅为
x
),并生成
out^
绑定的定义(
foo
bar
):

B
组件实际上需要分为两部分:一个是提供
x
定义的单元,另一个是使用
foo
bar
函数的单元。我简化了后一部分,只打印出结果,这样我就不必再创建另一个签名

(define-unit B-in@
  (import)
  (export in^)
  (define x "lala"))

(define-unit B@
  (import out^)
  (export)
  (printf "~a\n" (foo "lulu"))
  (printf "~a\n" (bar "lili")))
在本例中,可以从签名和单元定义自动推断链接。要将这些组件链接在一起并运行结果,只需执行以下操作:

(invoke-unit/infer (link A@ B-in@ B@))
这相当于调用以下复合单元(类似于functor应用程序),可以这样更明确地编写:

(invoke-unit (compound-unit/infer (import) (export) (link A@ B-in@ B@)))
除了让Racket推断链接之外,您还可以按如下方式显式编写:

(invoke-unit
 (compound-unit
   (import)
   (export)
   (link [((B-in : in^)) B-in@]
         [((A : out^)) A@ B-in]
         [() B@ A])))
您也可以在调用复合单元时从上下文中获取绑定,而不是创建显式单元来满足^导入中的
。例如:

(define-unit C@
  (import out^)
  (export)
  (printf "~a\n" (foo "really"))
  (printf "~a\n" (foo "nothing")))

(let ([x "empty"])   ;; the in^ bindings come from here!
  (invoke-unit
   (compound-unit/infer (import in^) (export) (link A@ C@))
   (import in^)))
另一种重要的特殊形式是
定义值/invoke unit
,它接受一个单元的导出并将其转换为正常的球拍定义

(let ([x "apple"])  ;; in in^ bindings come from here!
  (define-values/invoke-unit A@ (import in^) (export out^))
  ;; the out^ exports are available for the rest of the let body
  (foo "orange"))

如前所述,您需要一个与ML函子极其相似的函数。不过,在实践中,您通常可以避开或使用其他更简单的构造,因此单位在实践中并不常用。我阅读了有关参数的文章,但尚未对其进行研究。也许你可以在上面写一篇非常好的博文;-)不,真的谢谢你的指点。我会写一个真实的答案,但现在,我需要睡觉了如果我有机会的时候别人还没有,我会写一些东西。
(define-unit C@
  (import out^)
  (export)
  (printf "~a\n" (foo "really"))
  (printf "~a\n" (foo "nothing")))

(let ([x "empty"])   ;; the in^ bindings come from here!
  (invoke-unit
   (compound-unit/infer (import in^) (export) (link A@ C@))
   (import in^)))
(let ([x "apple"])  ;; in in^ bindings come from here!
  (define-values/invoke-unit A@ (import in^) (export out^))
  ;; the out^ exports are available for the rest of the let body
  (foo "orange"))