9

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?

l0b0
  • 55,365
  • 30
  • 138
  • 223
  • 1
    Aren't you looking for an unit-testing library like RackUnit (http://docs.racket-lang.org/rackunit/index.html) ? – Gabriel Ščerbák Aug 08 '11 at 10:43
  • It would be a last resort, because in languages like Python and Bash it would be overkill. – l0b0 Aug 08 '11 at 10:57
  • 1
    Basically what are you trying to do in bash, can be done directly in Scheme, to me your approach looks like overkill:) – Gabriel Ščerbák Aug 08 '11 at 11:42
  • How? The important points are that I want to be able to use any editor, and that the execution should stop as soon as one of the evaluations return `#f`. – l0b0 Aug 08 '11 at 11:58
  • 2
    If you don't want to touch the files I understand, but otherwise it is nonsense to use other language to parse Scheme files into expressions, feed them to scheme and then check the exit codes if you can just import a library, write checks in Scheme and you are done. The fail-fast is exactly what that library I linked does, look at section 3.1 – Gabriel Ščerbák Aug 08 '11 at 12:41
  • That's not at all what I want to do. I never wanted to parse Scheme in some other language, just run the file and stop at expressions which are false. If I run (= 1 2) in Scheme, it says the value is `#f`. I want it to do the same when using `--load` or something similar, and *stop evaluation there*. – l0b0 Aug 08 '11 at 13:08
  • @GabrielŠčerbák let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/2222/discussion-between-l0b0-and-gabriel-scerbak) – l0b0 Aug 08 '11 at 13:08

2 Answers2

5

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)

okonomichiyaki
  • 8,355
  • 39
  • 51
0

I can think of two ways. The brute-force way would be to write an expect script that runs scheme as an inferior process and feeds it a line at a time and checks the returned output -- basically, being a robot. The more elegant way would be to replace the top-level REPL in your scheme interpreter with one that exits if the expression evaluates to #f.

evil otto
  • 10,348
  • 25
  • 38