Осваиваю Lisp. В качестве первого упражнения решаю следующую задачу. Имеется текстовый файл с часами разработчика в формате
<дата> <модификатор деятельности> <количество часов> <описание>
(Файл может содержать комментарии, начинающие с знака «#».) Необходимо подсчитать общее количество часов работы.
Например, для файла
20.05.2011 RD 2 Чтение глав «Функции» и «Параметры» из PCL
20.05.2011 OT 1 Установка SBCL
20.05.2011 CO 2 Кодирование и отладка функции count-hours
Результат должен быть 5.
Вот мое решение:
;;;; Program reads file with working hours of developer
;;;; and outputs sum of hours.
;; Counts working hours from specified filename.
(defun count-hours (filename)
(let ((in (open filename :if-does-not-exist nil)) (hours 0))
(when in
(loop for line = (read-line in NIL) while line do
; Doesn't process line with comments and empty line
(if (not (or (= (length line) 0) (char= (elt line 0) #\#)))
(setf hours (+ hours (parse-integer (get-word line 3))))))
(close in)) hours))
;; Returns nth word in string. Words are separated by Space and Tab
(defun get-word (str num)
(let* ((white-spaces (list #\Space #\Tab)) (pos (get-white-space-min-pos white-spaces str)))
(if (not pos) "0"
(if (= (1- num) 0) (subseq str 0 pos)
(get-word (string-trim white-spaces (subseq str pos)) (1- num))))))
;; Returns minimum position in str of character from list of characters (white-spaces).
;; If str doesn't have characters from list then nil is returned.
(defun get-white-space-min-pos (white-spaces str)
(let ((min-pos NIL))
(dolist (white-space white-spaces)
(let ((pos (position white-space str)))
(if (not min-pos) (setf min-pos pos))
(if (and pos min-pos) (setf min-pos (min min-pos pos)))))
min-pos))
Запускать можно так:
(сount-hours «wh-dimv.txt»)
Собственно вопросы:
1. Не кажется ли вам, что здесь все написано в императивном стиле, просто с использованием скобочек? Если да, то направьте на путь истинный.
2. Есть ли в коде места, которые лучше было бы реализовать с помощью макросов? Я таких мест сейчас вижу, скорее всего, потому что слишком мало знаком с lisp. Или задача слишком маленькая, чтобы понадобились макросы?