LINUX.ORG.RU

Сообщения unwind-protect

 

Макрос do-stream

Ребята, практикуюсь в проектировании и реализации CL макросов. В стиле do-макросов (dolist, dotimes, ...) сделал вот такую штуку:

(defmacro do-stream ((var stream &key result (read-function '#'read-line) (eof nil eof-supplied-p)) &body body)
  (once-only ((stream stream)
              (read-function read-function))
    (with-gensyms (start)
      `(block nil
         (tagbody
            ,start
            (let ((,var
                   ,(if eof-supplied-p
                        (with-gensyms (%)
                          `(let ((,% (funcall ,read-function ,stream nil ,eof)))
                             (if (equal ,% ,eof)
                                 (return ,result)
                                 ,%)))
                        `(handler-case
                             (funcall ,read-function ,stream t)
                           (end-of-file () (return ,result))))))
              ,@body
              (go ,start)))))))

Раскрывается следующим образом. С eof так:

(with-open-file (s "input")
  (let (result)
    (do-stream (line s :result result :eof "Hello")
      (push line result))))

(WITH-OPEN-STREAM (S (OPEN "input"))
  (LET (RESULT)
    (LET ((#:STREAM953 S) (#:READ-FUNCTION954 #'READ-LINE))
      (BLOCK NIL
        (TAGBODY
         #:START955
          (LET ((LINE
                 (LET ((#:%956
                        (FUNCALL #:READ-FUNCTION954 #:STREAM953 NIL "Hello")))
                   (IF (EQUAL #:%956 "Hello")
                       (RETURN RESULT)
                       #:%956))))
            (PUSH LINE RESULT)
            (GO #:START955)))))))
Без eof, вот так:
(with-open-file (s "input")
  (let (result)
    (do-stream (item s :result result :read-function #'read)
      (declare (type (or symbol fixnum) item))
      (push item result))))

(WITH-OPEN-STREAM (S (OPEN "input"))
  (LET (RESULT)
    (LET ((#:STREAM944 S) (#:READ-FUNCTION945 #'READ))
      (BLOCK NIL
        (TAGBODY
         #:START946
          (LET ((ITEM
                 (HANDLER-CASE (FUNCALL #:READ-FUNCTION945 #:STREAM944 T)
                               (END-OF-FILE NIL (RETURN RESULT)))))
            (DECLARE (TYPE (OR SYMBOL FIXNUM) ITEM))
            (PUSH ITEM RESULT)
            (GO #:START946)))))))

Интересует мнение экспертов общелелиспа. С ходу вопросы такие:

  • Полезен ли такой макрос или в CL принято подобную логику обхода файла делать по другому?
  • Нормален ли макрос в плане дизайна? (вместе &optional аргумента result, сделал &key ввиду необходимости задания read-function и eof)
  • Нормален ли макрос в плане реализации? Какие есть косяки?
  • Есть ли подводные камни в обработке условия end-of-file при отсутствии eof?
  • Временную переменную (при наличии eof) задал как %. Это норм или в сообществе принято как-то по другому именовать?

    Любая конструктивная критика горячо приветствуется. Обсуждение решения подобного обхода файла на других диалектах Lisp также приветствуются, но всё же в первую очередь интересуют мнения общелисперов. Спасибо большое!

 ,

unwind-protect
()

RSS подписка на новые темы