在Racket脚本中调用`racket`命令

6

一般问题:

我能否在运行中的Racket脚本中调用当前的racket可执行文件?

基本上,如果(find-executable-path "racket")没有返回我当前使用的Racket可执行文件的路径,我想要一个替代(system "racket ...")

背景:

我真正想做的是尝试编译一些表达式,并断言它们会引发编译错误。这是为了单元测试。


1
顺便提一下,我知道Typed Racket可以解决这个问题,但我不理解解决方案。(这里的dr是什么?) - Ben Greenman
1
亲爱的过去的本,你会喜欢 find-console-bin-dirfind-exe 的。 - Ben Greenman
3个回答

5

我认为您不需要在此处执行外部操作。尝试这样做:

#lang racket

(require syntax/modread)

;; define a namespace anchor to attach a namespace to:
(define-namespace-anchor anchor)
;; define a namespace for expansion:
(define target-namespace (namespace-anchor->namespace anchor))

(define program-to-compile
  "#lang racket
(+ 3 4)")

;; go ahead and expand
(with-module-reading-parameterization
 (λ()
   (parameterize ([current-namespace target-namespace])
   (expand
    (read-syntax
     "bogus-filename"
     (open-input-string program-to-compile))))))

我认为,当我说Racket在提供编译器以有条理的方式运行程序方面非常纯净时,我的观点是正确的。


就此而言,Leif的回答比我的更高级,可能更接近你想要的! - John Clements

4
如果你只是想编译一些Racket表达式,你可以使用compile或者compile-syntax来实现。一个例子文件如下:
#lang racket
(require rackunit)

(define tests
  (list #'(+ 1 "3")
        #'(void void)
        #'(string-append 4)))

(for/list ([t (in-list test)])
  (check-exn exn:fail?
     (lambda () (compile t))))

在这里,exn:fail? 是你要查找的任何异常。

此外,如果你想在一些常见的语法上下文中运行测试,你可以使用 #` #,。因此,你的代码最终可能会像这样:

#lang racket
(require rackunit)

(define tests
  (list #'(+ 1 "3")
        #'(void void)
        #'(string-append 4)))

(for/list ([t (in-list test)])
  (check-exn exn:fail?
     (lambda () (compile #`(module anonymous racket
                             #,t)))))

最后,如果您的代码存储在计算机上,您可以使用John的解决方案,并使用file->string将文件转换为字符串。


如果我的“测试”在单独的文件中怎么办?我能否在文件名或端口上调用“编译”? - Ben Greenman

2
对于小型测试,您还可以使用来自 syntax/macro-testing 库的convert-compile-time-error。它将导致编译时错误的表达式转换为在评估时引发运行时错误的表达式。该表达式使用模块中出现的环境,包括局部绑定;您不必调整名称空间和eval
(check-exn #rx"bad syntax"
            (lambda () (convert-compile-time-error (lambda))))

同一页还有convert-syntax-error


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