4clojure#57 - 简单递归

时间:2015-05-12 18:54:07

标签: recursion clojure

我正在经历4个问题,我无法理解为什么following code is working

user=> ((fn foo [x] (when (> x 0) (conj (foo (dec x)) x))) 5)
(5 4 3 2 1)

我知道(foo (dec x))必须被视为PersistentCollection才能使其工作,但正在发生的事情是个谜。任何洞察它为什么工作,以及为什么在这个顺序将不胜感激。

2 个答案:

答案 0 :(得分:6)

让我们仔细看看您的代码示例。基本上,它只是一个带有以下(foo 5)函数的函数调用foo

(defn foo [x]
  (when (> x 0)
    (conj (foo (dec x)) x)))

当您使用foo的任何非正值调用x时,它会返回nil。否则,它会将conj oining x的结果返回到调用(foo (dec x))的结果。

因此,调用(foo 2)大致相当于以下代码:

(conj (conj nil 1) 2)

可能会让您感到困惑的是conj行为,nil值作为第一个参数传递。

conj个威胁nil作为空列表(),因此(conj nil 1)会产生与(conj () 1)相同的结果。 conj docs:

中记录了此行为
=> (doc conj)
(doc conj)
-------------------------
clojure.core/conj
([coll x] [coll x & xs])
  conj[oin]. Returns a new collection with the xs
    'added'. (conj nil item) returns (item).  The 'addition' may
    happen at different 'places' depending on the concrete type.

可能让您感到困惑的另一件事是结果列表中元素的顺序。 conj旨在以最有效的方式向PersistentCollection添加新元素。如果列表conj将新元素添加到原始列表的开头:

=> (conj '(1) 2)
(2 1)

答案 1 :(得分:3)

让我们打破这个:

(foo 5) ;;=>
(conj (foo 4) 5) ;;=>
(conj (conj (foo 3) 4) 5) ;;=>
...
(conj (conj (conj (conj (conj nil 1) 2) 3) 4) 5)
;; (conj nil 1) == '(1), so:
;;=>
(conj (conj (conj (conj '(1) 2) 3) 4) 5)
;; conj-ing adds to the head of the list
;;=>
(conj (conj (conj '(2 1) 3) 4) 5)
;;=> 
(conj (conj '(3 2 1) 4) 5)
...
;;=> '(5 4 3 2 1)