Избыточность примера Land of Lisp?

Я читал много хороших отзывов о Land of Lisp Вот я и подумал, что мог бы пройтись по нему, чтобы посмотреть, что там можно было увидеть.

(defun tweak-text (lst caps lit)
  (when lst
    (let ((item (car lst))
      (rest (cdr lst)))
      (cond 
       ; If item = space, then call recursively starting with ret
       ; Then, prepend the space on to the result.
       ((eq item #\space) (cons item (tweak-text rest caps lit)))
       ; if the item is an exclamation point.  Make sure that the
       ; next non-space is capitalized.
       ((member item '(#\! #\? #\.)) (cons item (tweak-text rest t lit)))
       ; if item = " then toggle whether we are in literal mode
       ((eq item #\") (tweak-text rest caps (not lit)))
       ; if literal mode, just add the item as is and continue
       (lit (cons item (tweak-text rest nil lit)))
       ; if either caps or literal mode = true capitalize it?
       ((or caps lit) (cons (char-upcase item) (tweak-text rest nil lit)))
       ; otherwise lower-case it.
       (t (cons (char-downcase item) (tweak-text rest nil nil)))))))

(комментарии мои)
(К сведению, сигнатура метода (list-of-symbols bool-whether-to-caps bool-whether-to-treat-literally), но автор сократил ее до (lst caps lit).)

Но в любом случае, вот вопрос:
Здесь есть (cond... (lit ...) ((or caps lit) ...)). Насколько я понимаю, это будет означать if(lit){ ... } else if(caps || lit){...} в синтаксисе стиля C. Тогда разве оператор or не является излишним? Есть ли когда-нибудь условие, при котором будет вызываться условие (or caps lit), если заглавные буквы равны nil?


person cwallenpoole    schedule 02.01.2011    source источник


Ответы (2)


Действительно, вы правы. См. ошибки для книги.

Страница 97: В функции tweak-text есть две ошибки, хотя она будет нормально работать в большинстве реализаций Лиспа. Прежде всего, он использует функцию eq для сравнения символов. Символы всегда следует проверять с помощью других функций, таких как eql или char-equal, в соответствии со спецификацией ANSI. Кроме того, есть ненужная галочка (или горящие заглавные буквы), которую можно упростить до заглавных букв.

person dsolimano    schedule 02.01.2011
comment
Спасибо. Я уже начал думать, что схожу с ума (в следующий раз не забуду сначала проверить ошибки) - person cwallenpoole; 02.01.2011
comment
Неработающая ссылка на ошибку? - person J. Mini; 29.06.2021
comment
@ J.Mini, кажется, работает нормально для меня, я все еще вижу страницу там. В любом случае весь текст скопирован сюда, так что ничего страшного, если ссылка не работает. - person dsolimano; 13.07.2021

Я бы написал так:

(defun tweak-text (list caps lit)
  (when list
    (destructuring-bind (item . rest) list
      (case item
        ((#\space)             (cons item (tweak-text rest caps lit)))
        ((#\! #\? #\.)         (cons item (tweak-text rest t    lit)))
        ((#\")                 (tweak-text rest caps (not lit)))
        (otherwise (cond (lit  (cons item (tweak-text rest nil  lit)))
                         (caps (cons (char-upcase item)
                                     (tweak-text rest nil lit)))
                         (t    (cons (char-downcase item)
                                     (tweak-text rest nil nil)))))))))

Оператор CASE отправляет символ. Затем оператор COND позаботится о других условиях. CASE сравнивается с EQL. Это означает, что CASE работает также для символов и даже может сравниваться с несколькими элементами. Я также поклонник стиля макета кода, который выстраивает соответствующие выражения — это полезно только с моноширинными шрифтами. Это помогает мне визуально обнаруживать шаблоны в коде и помогает обнаруживать код, который можно упростить.

DESTRUCTURING-BIND разделяет список.

Для развлечения переписано с использованием LOOP:

(defun tweak-text (list)
  (loop with caps and lit

        for item in list

        when (eql item #\space)
        collect item

        else when (member item '(#\! #\? #\.))
        collect item and do (setf caps t)

        else when (eql item #\")
        do (setf lit (not lit))

        else when lit
        collect item and do (setf caps nil)

        else when caps
        collect (char-upcase item) and do (setf caps nil)

        else
        collect (char-downcase item) and
        do (setf caps nil lit nil)))
person Rainer Joswig    schedule 02.01.2011
comment
'((Есть несколько вещей в книге, которые я отметил, я бы сделал по-другому (здесь у него есть немного рекурсии, где итерация намного чище и (на мой взгляд) легче понять))(но (я следую примеры (на всякий случай (у него план лучше, чем я бы придумал))))) (Lisp делает английский). - person cwallenpoole; 02.01.2011