Почему я не могу прочитать этот файл в Common Lisp?

Я пытаюсь читать файлы, используя Common Lisp with-open-file. В моей среде я использую SBCL, Emacs и Slime.

Я могу открывать такие файлы, как этот ( bookmarks-to-read.lisp), используя:

(defun read-my-file ()
  (with-open-file
   (stream "~/miscellaneous/misc/symbolic-computation/bookmarks-to-read.lisp")
    (let ((contents
            (read-all-objects stream (list '$eof$))))
      (format t "~&Read ~S objects from the file."
              (length contents))
      contents)))

(defun read-all-objects (stream eof-indicator)
  (let ((result (read stream nil eof-indicator)))
    (if (eq result eof-indicator)
        nil
        (cons result (read-all-objects stream eof-indicator)))))

После вызова функции в REPL я получаю ожидаемое содержимое:

CL-USER> (read-my-file)

Read 1 objects from the file.
(((:URL "https://calendar.google.com/calendar/u/0/r/week?pli=1" :TITLE
.
.
. 

(:URL "https://www.rescuetime.com/dashboard" :TITLE   
"RescueTime - Your Daily dashboard" :DATE
"2021-05-16T23:08:46.605691Z"    :TAGS ("rescue"))))

Обратите внимание, что это .lisp. Однако, если я попытаюсь сделать то же самое с этим другим файлом (history-to-read.lisp) Я получаю сообщение об ошибке.

Мне просто нужно изменить местоположение:

(defun read-my-file ()
  (with-open-file
   (stream "~/miscellaneous/misc/symbolic-computation/history-to-read.lisp")
    (let ((contents
            (read-all-objects stream (list '$eof$))))
      (format t "~&Read ~S objects from the file."
              (length contents))
      contents)))

(defun read-all-objects (stream eof-indicator)
  (let ((result (read stream nil eof-indicator)))
    (if (eq result eof-indicator)
        nil
        (cons result (read-all-objects stream eof-indicator))))

А потом, после вызова функции на REPL:

CL-USER> (read-my-file) ; Evaluation aborted on
#<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Package ~A does not exist." {1003AB9273}>.

Я получаю это сообщение об ошибке:

Пакет HISTORY-TREE не существует.

Строка: 3, столбец: 45, позиция в файле: 110

Поток: #‹SB-SYS:FD-STREAM для файла /home/pedro/miscellaneous/misc/symbolic-computation/history-to-read.lisp {1003AB83A3}› [Условие типа SB-INT:SIMPLE-READER-PACKAGE -ОШИБКА]

ИСТОРИЯ-ДЕРЕВО - это просто то, что было написано в тексте. Например, foo.

Кроме того, я попытался воспроизвести предложение, описанное @RainerJoswig здесь. К сожалению, возникла та же проблема.

1 - Поскольку оба файла .lisp и функция их чтения одна и та же, почему это происходит?

2 - Почему здесь важен смысл/содержание текста?

3 - И как я могу прочитать этот файл?


person Pedro Delfino    schedule 05.06.2021    source источник


Ответы (1)


Пакет HISTORY-TREE не существует

Это сообщение ясно: пакет HISTORY-TREE не существует. А вы попробуйте в этот несуществующий пакет прочитать символы, например HISTORY-TREE:OWNER.

Каждый пакет, упомянутый в печатном символе в этом файле, должен существовать, прежде чем можно будет успешно прочитать файл.

Программа чтения Common Lisp по умолчанию не создает пакеты на лету, просто читая символы.

Пример:

CL-USER 130 > (read-from-string "bar::foo")

Error: Reader cannot find package BAR.
  1 (continue) Create the BAR package.
  2 Use another package instead of BAR.
  3 Try finding package BAR again.
  4 (abort) Return to top loop level 0.

Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.

теперь давайте воспользуемся перезапуском ошибки, чтобы создать этот пакет:

CL-USER 131 : 1 > :c 1
BAR::FOO
8

Альтернативные решения:

  1. создавать пакеты перед чтением данных
  2. не печатать символы с префиксами пакетов
  3. использовать пользовательский ридер, который может создавать пакеты или помечать символы как имеющие неопределенный пакет

Примечания

(defun read-all-objects (stream eof-indicator)
  (let ((result (read stream nil eof-indicator)))
    (if (eq result eof-indicator)
        nil
        (cons result (read-all-objects stream eof-indicator))))

Например, можно было бы написать что-то вроде этого:

(defun read-all-objects (stream &aux (eof '#:eof))
  (loop for item = (read stream nil eof)
        until (eq item eof)
        collect item))

Преимущества:

  • аргумент EOF не требуется, здесь мы используем неинтернированный символ
  • количество элементов списка не ограничено глубиной стека
person Rainer Joswig    schedule 06.06.2021