Search code examples
shellubuntuschemesicp

Run SICP Scheme files like fast-failing tests


After a few years of programming it seems time to finally attack SICP. However, instead of editing and running everything in Emacs, I'd rather use a different editor and a simple makefile to run all the exercises. This doesn't seem to be entirely canon, because I couldn't find any reference to something as basic as running a file until something "fails". So how do I run Scheme on the shell so that it loads a file, evaluates each expression in sequence, and terminates with a non-zero exit code as soon as it encounters a statement which evaluates to #f or with an exit code of zero if the entire file was evaluated successfully? The closest thing to a solution so far:

$ cat ch1.scm
...
(= 1 2)
$ scheme --load ch1.scm
...
Loading "ch1.scm"... done

1 ]=>

Edit: In other words, is there some way to make evaluation stop during the loading of ch1.scm if any of the expressions therein evaluate to #f?


Solution

  • One option if you don't want to resort to a full-blown unit-testing library (understandable) is to write your own. You can use read to read s-expressions from the file, use eval to evaluate them and test if they are false, and report back, quitting if you find a false. Something like this should work:

    (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)))))))))
    

    If you put the above in a file called unit.scm and the file you want to test is called test.scm, you can call this with MIT Scheme from the Unix command line like so:

    mit-scheme --load `pwd`/unit.scm --eval '(read-and-test "/Users/aki/code/scratch/test.scm" (the-environment))'
    

    (note there's some MIT Scheme specific things above, related to eval and enviroments)