Clojure括号问题一则

把下面的common lisp代码用Clojure来写

 
(defun qsort (l)
  (cond
    ((null l) nil)
    (t
      (append
        (qsort (list< (car l) (cdr l)))
        (cons (car l) nil) 
        (qsort (list>= (car l) (cdr l)))))))
 
 
(defun list< (a l)
  (cond
    ((or (null a)(null l)) nil)
    (( < a (car l)) (list< a (cdr l)))
    (t (cons (car l) (list< a (cdr l))))))
 
(defun list>= (a l)
  (cond
    ((or ( null a)(null l)) nil)
    (( >= a (car l)) (list>= a (cdr l)))
    (t (cons (car l) (list>= a (cdr l))))))
 

结果硬是写成了下面这样

 
 
(defn list< [a l]
  (println l)
  (filter #(< % a) l) 
)
 
(defn list>= [a l]
  (filter #(>= % a) l) 
)
 
(defn qsort [l]
  ;(println l)
  (cond
    (empty? l) '())
    :otherwise  (concat (qsort (list< (first l) (rest l)))
                        (cons (first l) nil)
                        (qsort (list>= (first l) (rest l))))
)
 

qsort中cond的第一条语句后面 多了一个右括号, 提前结束了cond宏, 输入'()的时候会导致死循环, 因为这里即使提前结束cond, 但是总的括号数量正确的话, 仍然会是合法的代码. 实际变成了

 
(defn qsort [l]
  ;(println l)
  (cond
    (empty? l) '())
  :otherwise
  (concat (qsort (list< (first l) (rest l)))
                 (cons (first l) nil)
                 (qsort (list>= (first l) (rest l)))
  )
)
 

而肉眼则完全没有察觉出来, 导致我一开始还怀疑Clojure的cond宏的实现和common lisp有所不同. 我想的是, cond中没有命中的条件中, 如果有递归调用, 那么递归调用仍然会执行. 实际上cond宏就是封装了嵌套的if语句而已, 没有命中条件的语句绝对不会执行的.

而且这样的错误写法并不是第一次碰到, 上次在某个地方遇到了相同的问题. 在LISP当中, 也算是一种bug的来源, 那就是括号匹配明明错了, 但是代码上看不出来, 而且仍然是合法的代码, 可以执行, 但是会出现奇怪的错误, 一般情况下又不会想到是括号写错了, 这种情况往往意味着长时间的debug.