4clojure #57 - 简单递归

4clojure #57 - Simple Recursion

我正在经历 4 个 clojure 问题,我不明白为什么 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 才能正常工作,但那里发生的事情是个谜。任何了解它为什么工作以及为什么按此顺序工作的任何见解都将不胜感激。

我们来分解一下:

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

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

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

当您使用 x 的任何非正值调用 foo 时,它 returns nil。否则它 return conj 加入 x 到调用 (foo (dec x)).

的结果

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

(conj (conj nil 1) 2)

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

conj 威胁 nil 作为空列表 (),因此 (conj nil 1) 产生与 (conj () 1) 相同的结果。此行为记录在 conj 文档中:

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