Land of Lisp пример избыточности? - PullRequest
10 голосов
/ 02 января 2011

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

(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 caps lit), если caps равен nil?

Ответы [ 2 ]

10 голосов
/ 02 января 2011

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

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

8 голосов
/ 02 января 2011

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

(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 разбирает список на части.

Для fun , переписано с использованием 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)))
...