2

I wrote down this iterative code in LISP using the loop function:

(defun loadfile (filename)
  (with-open-file (stream filename)
    (loop for line = (read-line stream nil 'eof)
          until (eq line 'eof)
          collect line)))
    )
  )

Is there a way to rewrite it without loop, in a recursive way?

4
  • Yes, but does it look like a task that requires a recursive approach? Commented Jan 10, 2018 at 13:03
  • yes, i did using loop but the task (unfortunately) clearly says "don't use LOOP, DO, DOLIST, DOTIMES" Commented Jan 10, 2018 at 13:08
  • 4
    I see; note that apparently there is no restriction about tagbody ;-) Commented Jan 10, 2018 at 13:16
  • Ah allright this is homework right ? To do this in two lines in real life, I suggest this: stackoverflow.com/questions/3813895/… Commented Jan 10, 2018 at 23:17

2 Answers 2

6

Surprise them with a GOTO instead:

(defun loadfile (filename)
  (with-open-file (stream filename)
    (prog (line lines)
      repeat
      (setf line (read-line stream nil))
      (when line
        (push line lines)
        (go repeat))
      (return (reverse lines)))))
Sign up to request clarification or add additional context in comments.

Comments

5

Of course any loop can be transformed in recursion, but reading an entire file a line at time, is, however, a typical iterative process, so I find this question difficult to motivate.

Here is a possible recursive version, where the recursion is managed by an internal function:

(defun load-file (filename)
  (with-open-file (stream filename)
    (labels ((read-recursively ()
               (let ((line (read-line stream nil 'eof)))
                 (if (eq line 'eof)
                     nil
                     (cons line (read-recursively))))))
      (read-recursively))))

This solution is prone to a stack-overflow error if the number of rows of the file is big.

If one has a compiler which can perform tail optimization, the following alternative recursive solution could be compiled in iterative fashion and could avoid the stack-overflow:

(defun load-file (filename)
  (with-open-file (stream filename)
    (labels ((read-recursively (read-so-far)
               (let ((line (read-line stream nil 'eof)))
                 (if (eq line 'eof)
                     (reverse read-so-far)
                     (read-recursively (cons line read-so-far))))))
      (read-recursively ()))))

3 Comments

File has to contain just one row (probably a long one), so i think that each one of the two solutions can be used, am i correct?
@DouglasP Only one row? then why loop, just call read-line once
Yes but i want to try something in case i have more rows. thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.