我正在经历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才能使其工作,但正在发生的事情是个谜。任何洞察它为什么工作,以及为什么在这个顺序将不胜感激。
答案 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)