像快速失败的测试一样运行SICP Scheme文件

9
几年的编程之后,我决定攻略SICP了(译者注:《计算机程序的构造和解释》)。不过,我不想在Emacs中编辑和运行所有的内容,我想用另一种编辑器,再加上一个简单的makefile来运行所有的练习。但是这好像并不是官方做法,因为我没找到任何关于如何运行文件的基础知识,直到“失败”才停止。那么,我应该怎样在shell中运行Scheme呢?使它依次加载每个表达式,并在遇到一个评估结果为#f的语句时以非零的退出代码终止,或者如果整个文件都被成功评估,则以零的退出代码终止?目前最接近解决的方法是:
$ cat ch1.scm
...
(= 1 2)
$ scheme --load ch1.scm
...
Loading "ch1.scm"... done

1 ]=>

编辑:换句话说,如果 ch1.scm 中的任何表达式求值为 #f,是否有一种方法使评估在加载期间停止?

1
你难道不是在寻找像RackUnit(http://docs.racket-lang.org/rackunit/index.html)这样的单元测试库吗? - Gabriel Ščerbák
这将是最后的选择,因为在像Python和Bash这样的语言中,这将是过度杀伤力的。 - l0b0
1
基本上你在bash中想做的事情,在Scheme中可以直接完成,对我来说,你的方法看起来有些过度。 :) - Gabriel Ščerbák
如何实现?重要的是我想能够使用任何编辑器,并且只要有一个评估返回“#f”,执行就应该停止。 - l0b0
2
如果您不想触碰文件,我理解,但是否则使用其他语言来解析Scheme文件为表达式,将它们提供给Scheme,然后检查退出代码是没有意义的,因为您可以只需导入库,在Scheme中编写检查即可完成。故障快速就是我链接的那个库所做的事情,看看第3.1节即可。 - Gabriel Ščerbák
显示剩余2条评论
2个回答

5

如果您不想使用完整的单元测试库(可以理解),那么一种选择是编写自己的测试代码。您可以使用read函数从文件中读取s表达式,使用eval函数来评估它们并测试它们是否为假,然后返回结果,如果找到一个假的就退出。下面这样的代码应该能够胜任:

(define (read-and-test filename env)
  (call-with-input-file
      filename
    (lambda (in)
      (let loop ((input (read in)))
        (if (eof-object? input)
            (display "done!")
            (begin
              (if (eval input env)
                  (begin
                    (display input)
                    (display " ok")
                    (newline)
                    (loop (read in)))
                  (begin
                    (display "failed on ")
                    (display input)
                    (newline)
                    (exit)))))))))

如果你把上述内容放在一个名为unit.scm的文件中,要测试的文件名叫做test.scm,你可以在Unix命令行中使用MIT Scheme调用它,如下所示:
mit-scheme --load `pwd`/unit.scm --eval '(read-and-test "/Users/aki/code/scratch/test.scm" (the-environment))'

(注意上面有一些与eval和环境相关的MIT Scheme特定内容)
请注意,上面有一些与eval和环境相关的MIT Scheme特定内容。

0
我能想到两种方法。一种是蛮力法,即编写一个 expect 脚本,将 scheme 作为下级进程运行,并逐行输入并检查返回的输出——基本上就像一个机器人。更优雅的方法是用一个退出表达式评估为 #f 的顶层 REPL 替换你的 scheme 解释器。

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