如何在Racket(X)REPL中重新加载文件?

14

假设我有一个像这样的文件

#lang racket/base
(define (hello) (print "Hello"))
... more definitions ...

我希望能够加载文件中的定义,并在(X)REPL中与它们进行交互操作。我该如何做?

如果我在(X)REPL中输入(load "/tmp/hello.rkt"),那么hello函数对我来说是不可用的:

-> (hello)
; hello: undefined;
如果我使用(require (file "/tmp/hello.rkt")), 结果是一样的。现在我可以使用(enter! (file "/tmp/hello.rkt")), 然后(hello)可以运行,但这似乎不太直观和适合初学者。
这确实是应该进行的方式吗?是否应该简单地查阅模块和命名空间以轻松浏览和测试我的代码或者是否有我忽略的更简单的方法?
注:我发现如何通过命令行将文件加载到Racket中?,但那只解释了如何运行文件,而没有讲述如何在REPL中加载它,以便您可以测试/调试特定定义,然后编辑、重新加载等。
2个回答

15

由于以 #lang 开头的文件是模块,因此如果您使用 load 加载它们,则不会发生任何事情。(实际上它确实有作用,但可能对您没有帮助。)最好完全避免使用 load,就像它不存在一样。

现在,使用 require 是正确的做法,但它所做的是实例化模块并使您可以访问它提供的名称。在您的情况下,您没有提供任何东西,这意味着您无法使用您的 hello。为了解决这个问题,您可以向文件添加 (provide hello)。但这很可能不是您想要的,因为似乎您想要调试代码。(即,您不想提供模块中的所有内容来处理事情。)

因此,正确的方法是使用 enter!,或者如果您正在使用 xrepl,则有一个更方便的 ,en 命令。这将实例化模块并使 repl 使用模块的命名空间,因此您可以访问所有内容。(而且您不需要 loadrequire 它。)您还可以多次使用它来重新加载代码,如果您更改了代码的话。但请注意,它存在一些问题,所以您可能需要安装一个夜间版本 来使用它。

最后,您可能已经知道,但通常使用 DrRacket 会使事情更加容易。


好的,那就用 enter! 吧。我使用 (X)REPL 的原因是我正在使用 charterm 包来实现我的程序的 CLI 接口,而该包无法在 DrRacket 中使用(这很合理,因为 DrRacket 不提供 tty)。 - Confusion
它的使用方式如下:(enter! "file.rkt") 或者使用简单版本,无需括号和引号:,en file.rkt - vlz

3
#lang racket/base放在文件顶部,标记该文件为模块形式(这是#lang缩写);因此,加载文件只是为(file "/tmp/hello.rkt")添加模块定义,就像你要求该路径时发现的那样。
如果你只想尝试一组定义,并尝试交互式加载它们,可以尝试删除代码文件顶部的#lang racket / base。我在这里用一对“Racket toplevel”(rktl)文件进行说明:
% cat hello-unhashed.rktl
(define (hello) (print "Hello") (newline))
% cat hello2-unhashed.rktl
(define (hello) (print "Hello2") (newline))
% racket
Welcome to Racket v5.3.2.
> (load "hello-unhashed.rktl")
> (hello)
"Hello"
> (load "hello2-unhashed.rktl")
> (hello)
"Hello2"
> (load "hello-unhashed.rktl")
> (hello)
"Hello"
> (exit)
% 

请注意,以上述方式在顶层工作时存在许多陷阱。为了更好地理解我的意思,请尝试谷歌搜索“racket top level is hopeless”或“plt scheme top level is hopeless”。

这个来自Racket开发者之一的Gist还提供了一个“toplevel is hopeless”模因的不错索引:https://gist.github.com/samth/3083053 - pnkfelix
永远不应该推荐使用 load。就像 eval 一样,那些可能会发现它有用的人都足够了解它们而不必问及其使用方式,所以仅通过询问有关它的信息就可以知道不应该建议使用它(顺便说一下,由于这些“toplevel”文件非常不同,因此我们使用 .rktl 作为它们的后缀)。 - Eli Barzilay
啊,我不知道.rktl的惯例。我会编辑我的答案,至少对我创建的文件使用它。最初的问题是使用load开始的,我只是跟进了这个问题;我会让提问者决定我们给出的两种方法中哪一种回答了他们的问题。 - pnkfelix
2
我对此的看法是,loadeval 一样糟糕。一方面,它经常被滥用,这使得它更糟糕,但另一方面,人们在使用 load 时没有像使用 eval 那样的抑制力...无论如何,在 Racket 中使用 load 对于那些会询问它的人来说肯定是一个错误。(也就是说,有一些有效的用途,但那些只有专家才会做的事情。) - Eli Barzilay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接