;;; Procedure: ;;; sum-of-file ;;; Parameters: ;;; file-name, a string that names a file. ;;; Purpose: ;;; Sums the values in the given file. ;;; Produces: ;;; sum, a number. ;;; Preconditions: ;;; file-name names a file. [Unverified] ;;; That file contains only numbers. [Verified] ;;; Postconditions: ;;; Returns a number. ;;; That number is the sum of all the numbers in the file. ;;; Does not affect the file. (define sum-of-file (lambda (file-name) (let* ((source (open-input-file file-name)) (result (sum-of-file-kernel file-name source))) (close-input-port source) result))) ;;; Helper: ;;; sum-of-file-kernel ;;; Notes: ;;; A lot like sum-of-file, except that it reads the values from ;;; an open input port rather than a file name. (The file name ;;; is also passed in so that it can be used for error messages.) ;;; Does not verify that the input port is open. ;;; Crashes (with an error message) if the file contains ;;; non-numbers. In that case, it still closes the input port. (define sum-of-file-kernel ; A helper to a helper. Used only when we need to crash and burn. (let ((failure (lambda (file-name source) (close-input-port source) (error "sum-of-file" (string-append "The file " file-name " contains a non-number."))))) (lambda (file-name source) ; Read a value from the port. (let ((nextval (read source))) (cond ; Are we at the end of the file? Then stop and return 0 for ; "no numbers read". Here, we're taking advantage of 0 being ; the arithmetic identity. ((eof-object? nextval) 0) ; Have we just read a number? If so, add it to the sum of the ; remaining numbers. ((number? nextval) (+ nextval (sum-of-file-kernel file-name source))) ; Hmmm ... something has gone horribly wrong. (else (failure file-name source)))))))