Search code examples
lispcommon-lispclisp

Clisp reading list from file and flatten it, but not working, doesnt recognize lst as a list


(defun read-file-list (infile)
  (with-open-file (instream infile :direction :input :if-does-not-exist nil)
   (when instream 
     (let ((list (make-list (file-length instream))))
       (read-sequence list instream)
       list))))


(setq lst (read-file-list "/home/Desktop/nested_list.txt"))

(flatten-list lst )

(print lst)

;(1 2 3 (4 5 (12 11 9 6) 4 8 (77 53(47)) (12 15 18)) 
; file has got this line

Solution

  • READ-SEQUENCE reads characters from a file. When you compute the file-length and call read-sequence, all you are doing is reading all characters in a flat list. Namely, lst in your example is this list:

    (#\( #\1 #\  #\2 #\  #\3 #\  #\( #\4 #\  #\5 #\  #\( #\1 #\2 #\  #\1 #\1 #\
     #\9 #\  #\6 #\) #\  #\4 #\  #\8 #\  #\( #\7 #\7 #\  #\5 #\3 #\( #\4 #\7 #\)
     #\) #\  #\( #\1 #\2 #\  #\1 #\5 #\  #\1 #\8 #\) #\) #\Newline)
    

    You can see that all elements in this list are characters, they are denoted with the #\... syntax. For example, the first item is described as follow (tested with SBCL, actual output may vary in your implementation):

    * (describe (first lst))
    #\(
    [standard-char]
    
    Char-code: 40
    Char-name: LEFT_PARENTHESIS
    ; No value
    

    (with-open-file (stream "/tmp/file-list.txt") (read (make-concatenated-stream (make-string-input-stream "(") stream (make-string-input-stream ")")))) What you want to do is to call READ on that file:

    * (with-open-file (in "/tmp/file-list.txt")
        (read in))
    ; Evaluation aborted on #<END-OF-FILE {1013420B23}>.
    

    And it appears also your input file misses a closing parenthesis. After fixing that, you have:

    * (with-open-file (in "/tmp/file-list.txt")
        (read in))
    (1 2 3 (4 5 (12 11 9 6) 4 8 (77 53 (47)) (12 15 18)))
    

    Here the read value is a list of numbers and nested lists.

    * (describe (first *))
    1
    [fixnum]
    ; No value
    

    ---- Edit

    Your flatten-list function seems to work, what I am saying is that your input list is in another file, and that you need to extract the data using the standard Lisp reader by calling read:

    * (with-open-file (in "/tmp/file-list.txt")
        (flatten-list (read in)))
    
    (1 2 3 4 5 12 11 9 6 4 8 77 53 47 12 15 18)
    

    --- Edit 2

    If your file contains the list elements, like this:

    1 2 3 (4 5 (12 11 9 6) 4 8 (77 53(47)) (12 15 18))
    

    Then you could write a loop, as follows:

    (loop 
      for form = (read in nil in)
      until (eq form in)
      collect form)
    

    Or, you could use a concatenated stream:

    USER> (with-input-from-string (open "(")
            (with-input-from-string (close ")")
              (with-open-file (file "/tmp/file-list.txt")
                (read (make-concatenated-stream open file close)))))
    (1 2 3 (4 5 (12 11 9 6) 4 8 (77 53 (47)) (12 15 18)))
    

    Or equivalently:

    (with-open-file (stream "/tmp/file-list.txt")
      (read (make-concatenated-stream (make-string-input-stream "(")
                                      stream
                                      (make-string-input-stream ")"))))