Lisp之地示例中的冗余?

10

我已经阅读了很多关于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) ...))。我的理解是,在C风格的语法中,这将被翻译为if(lit){ ... } else if(caps || lit){...}。那么or语句是否多余呢?如果caps是nil,是否会出现调用(or caps lit)条件的情况?
2个回答

10

确实如你所说。请查看勘误表以获取该书的更正。

第97页:函数tweak-text有两个小错误,但它可以在大多数Lisp实现上运行良好。首先,它使用eq函数比较字符——根据ANSI规范,应该使用其他函数(如eql或char-equal)来检查字符。此外,还有一个不必要的检查(or caps lit),可以简化为caps。


谢谢。我开始觉得自己快疯了(下次我会先检查勘误表)。 - cwallenpoole
错误的勘误链接? - J. Mini
@J.Mini 对我来说似乎很好,我仍然看到页面在那里。无论如何,整个文本都被复制在这里,所以如果链接失效,我们也没问题。 - dsolimano

8
我会将其写成以下内容:
(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)))

1
'((在这本书中,有几件事情我注意到了,我会做得不同(他在这里使用了一点递归,而迭代更简洁,而且(在我看来)更易于理解),但是(我正在跟随例子(以防万一(他可能有比我想出的更好的计划))))(Lisp讲英语)。' - cwallenpoole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接