我正在使用 Racket 制作一个应用程序,其中 Racket 也用作脚本语言。我希望用户利用我的可执行文件中提供的一些结构和过程来编写脚本。
例如我有
userruntime.rkt
:
(struct result (x y z))
(provide (all-from-out racket/base))
(provide (struct-out result))
用户写道
script.rkt
:
(define (my-even? x)
(if (eq? x 0) #t
(not (my-odd? (sub1 x)))))
(define (my-odd? x)
(not (my-even? (sub1 x))))
(result (my-odd? 1) (my-odd? 2) (my-odd? 3))
我想评估以下结果(你明白了):
'(#<void> #<void> (result #t #f #t))
看来
make-module-evaluator
中的racket/sandbox
满足了我的需求。但是,我未能找到传递模块的方法(作为最终可执行文件中编译和链接的文件)。官方文档给出了以下示例:
(define base-module-eval
(make-evaluator 'racket/base '(define (f) later)
'(define later 5)))
这不需要文件。当我尝试时:
(make-module-evaluator "userruntime.rkt") ; make-module-evaluator: expecting a `module' program; got userruntime.rkt [,bt for context]
;; or
(make-module-evaluator 'userruntime) ; make-module-evaluator: expecting a `module' program; got userruntime[,bt for context]
如何正确引用文件中的模块?预先感谢。
如果
module-decl
的 make-module-evaluator
参数是字符串,则它们将被视为要评估的代码。您必须传递一个 path 才能将其视为要读取的文件(或打开的输入端口(就我个人而言,我发现 make-evaluator
更容易使用,但它对其 input-program
有相同的要求)争论。)
此外,您的
script.rkt
在其函数定义中具有无限循环,您不应该使用 eq?
来比较数字,并且评估的代码没有像 REPL 那样打印出其顶级值 - 更好地包装函数中的代码并调用它。
有了这个
userruntime.rkt
:
#lang racket/base
(provide (struct-out result))
(struct result (x y z) #:transparent)
并且这个已修复
script.rkt
:
(define (my-even? x)
(if (= x 0)
#t
(my-odd? (sub1 x))))
(define (my-odd? x)
(if (= x 0)
#f
(my-even? (sub1 x))))
(define (callback)
(result (my-odd? 1) (my-odd? 2) (my-odd? 3)))
此代码有效:
(define evaluator
(make-evaluator 'racket/base (string->path "script.rkt")
#:requires '("userruntime.rkt")))
(println (evaluator '(callback))) ; (result #t #f #t)