动态 - 需要一个关于Racket中当前模块路径的模块(或者如何在Racket中找到当前模块路径)

时间:2017-03-06 18:21:47

标签: module racket

如果我想在运行时选择性地需要模块,我可以使用[dynamic-require' 1。如果我想要一个已经安装的软件包,这很有用,例如:

(dynamic-require 'racket/match 'match)

这将(假设我已安装racket/match),需要racket/match并评估该库中的match绑定。

但是,当我想要一个本地的,未安装的模块时,我遇到了麻烦。我们假设我有一个名为eat.rkt的模块,它提供了一个功能:bite

#lang racket ;; eat.rkt
(provide bite)
(define (bite) "Nom nom")

现在假设我们要创建一个需要lunch.rkt的{​​{1}}模块,然后调用该函数。此外,假设我将它们放在同一目录中:

eat.rkt

这很好,因为我使用了静态需求,但是当我想要#lang racket ;; lunch.rkt (require "eat.rkt") (bite) ; => Nom Nom 时,这会崩溃:

dynamic-require

虽然看起来很好,但事实证明#lang racket ;; lunch2.rkt (define bite (dynamic-require "eat.rkt" 'bite) (bite) ; => Nom Nom 所需的模块不是基于模块的路径所必需的,而是current-directory。所以,如果我在定义模块的目录中运行程序,那很好,但是如果我在另一个目录中,一切都会中断:

dynamic-require

显然我可以将$ racket lunch2.rkt "Nom Nom" $ cd snacks/ $ racket ../lunch2.rkt ; default-load-handler: cannot open module file 更改为此模块的目录,如果我知道它在哪里。但如果我不知道这个模块的路径,有什么方法可以得到它吗?或者,更直接地说,是否可以current-directory模块相对于需要的模块路径?

2 个答案:

答案 0 :(得分:2)

define-runtime-path表单定义了一个在运行时可用的路径,它独立于current-directory。使用它来定义动态需要的模块的路径,例如:

#lang racket
(require racket/runtime-path)
(define-runtime-path eat "eat.rkt")
(dynamic-require eat 'bite)

答案 1 :(得分:1)

dynamic-require模块相对于当前模块路径(也就是说保存模块的路径)的最简单方法是获取该模块路径并将其附加到相关模块。

您可以使用#%variable-referencevariable-reference->module-path-index执行此操作。 (您可能还希望将variable-reference->resolved-module-path用于其他情况,但我们不会在此处执行此操作。)通过编写这两个函数,我们可以为正在定义的模块提供module-path-index?。 (或者一般来说,#%variable-reference来自的模块。)

所以,我们可以像一个变量:

(define here (variable-reference->module-path-index (#%variable-reference)))

现在剩下的就是将这个here路径与我们想要的模块的相对路径组合在一起。我们正在寻找build-path的模块路径类比,如果你愿意的话。

事实证明,我们正在寻找的函数是:module-path-index-join,它采用基本路径和相对路径并将它们附加在一起。结果将类似于:

(module-path-index-join "eat.rkt" here)

(是的,它是你对build-path的期望的倒退,但是这个函数的基本路径是第二位。)

生成的模块lunch3.rkt如下所示:

#lang racket
(define here (variable-reference->module-path-index (#%variable-reference)))
(define bite (dynamic-require (module-path-index-join "eat.rkt" here) 'bite))

现在lunch3.rkt需要eat.rkt相对于其定义的位置,而不是基于current-directory

$ racket lunch3.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch3.rkt
"Nom Nom"

感谢Matthew Flatt帮助解决这个问题。