【问题标题】:Land of Lisp example redundency?Lisp 示例冗余之地?
【发布时间】:2011-01-02 00:58:00
【问题描述】:

我已经很多阅读了关于 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)))))))

(cmets 是我的)
(仅供参考——方法签名是(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) 条件?

【问题讨论】:

    标签: lisp common-lisp clisp land-of-lisp


    【解决方案1】:

    确实,你是对的。请参阅errata 获取本书。

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

    【讨论】:

    • 谢谢。我开始觉得我快疯了(下次我会记得先检查勘误表)
    • 错误的勘误链接?
    • @J.Mini 对我来说似乎工作正常,我仍然看到那里的页面。无论哪种方式,整个文本都被复制到这里,所以如果链接断开,我们可以。
    【解决方案2】:

    我会这样写:

    (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)))
    

    【讨论】:

    • '((书中有几件事我已经注意到我会做不同的事情(他在这里有一点递归,迭代更清晰并且(在我看来)更容易掌握) )(但是(我正在遵循示例(以防万一(他的计划比我想出的更好)))))(Lisp会说英语)。