1
votes

I am experimenting with Scheme (MIT/GNU Scheme 9.1) and I am writing some simple procedures to read and write files.

In order to read all the lines contained in a file into a list I have written the following:

(define read-lines-from-port-impl
        (lambda (file-input-port)
                (let* ((line (read-line file-input-port))
                      )
                      (if (eof-object? line)
                          (list)
                          (cons line (read-lines-from-port-impl file-input-port))
                      )
                )
        )
)


(define read-lines-from-port
        (lambda (file-port)
                (if (input-port? file-port)
                    (read-lines-from-port-impl file-port)
                    (list)
                )
        )
)


(define read-lines-from-file
        (lambda (filename)
                (call-with-input-file filename read-lines-from-port)
        )
)

Question 1

This seems to work but maybe there is a more idiomatic / concise way of doing this in Scheme. Can you suggest how to improve this code?

Question 2

In the above code I have used call-with-input-file which takes care of opening an input port before calling read-lines-from-port and of closing it after that procedure has completed.

If I wanted to open and close an input port myself using open-input-file and close-input-port, how would I write this in Scheme? I mean I have to

  • call open-input-file
  • read the lines from the resulting port
  • call close-input-port

In Haskell i would use the do notation, but how do I specify such a sequence of actions in Scheme?

1

1 Answers

2
votes

I didn't test this code, but even if I got something wrong, you should be able to figure it out from here:

; read-lines [port-or-filename] -- defaults to current input
(define (read-lines . args)
  (let ((p (cond ((null? args) (current-input-port))
                 ((port? (car args)) (car args))
                 ((string? (car args)) (open-input-file (car args)))
                 (else (error 'read-lines "bad argument")))))
    (let loop ((line (read-line p)) (lines (list)))
      (if (eof-object? line)
          (begin (if (and (pair? args) (string? (car args)))
                   (close-input-port p))
                 (reverse lines))
          (loop (read-line p) (cons line lines))))))

You write a sequence of statements using begin, as shown above.