在“ Clojure的喜悦”,第二版中,第133页介绍了quicksort的代码,我很难理解。我有rewritten it要更清楚(至少对我自己来说)。
以下是原图:
(defn sort-parts-joc [work]
(lazy-seq
(loop [[part & parts] work]
(if-let [[pivot & xs] (seq part)]
(let [smaller? #(< % pivot)]
(recur (list*
(filter smaller? xs)
pivot
(remove smaller? xs)
parts)))
(when-let [[x & parts] parts]
(cons x (sort-parts-joc parts)))))))
这是重写的代码:
(defn sort-parts-explicit-lazy [work]
(lazy-seq
(loop [loopwork work]
(let [[ part & partz ] loopwork ]
(if-let [[pivot & valuez] (seq part)]
(let [ smaller? #(< % pivot)
smz (filter smaller? valuez)
lgz (remove smaller? valuez)
nxxt (list* smz pivot lgz partz) ]
(recur nxxt))
(if-let [[oldpivot & rightpartz] partz]
(cons oldpivot (sort-parts-explicit-lazy rightpartz))
[]))))))
测试:
(require '( clojure test ))
(clojure.test/is (is-sorted (sort-parts-explicit-lazy [[]])))
(clojure.test/is (is-sorted (sort-parts-explicit-lazy [[1]])))
(clojure.test/is (is-sorted (sort-parts-explicit-lazy [[1 2]])))
(clojure.test/is (is-sorted (sort-parts-explicit-lazy [[1 2 3]])))
(clojure.test/is (is-sorted (sort-parts-explicit-lazy [[3 2 1]])))
(clojure.test/is (is-sorted (sort-parts-explicit-lazy [[3 3 3]])))
所以,它有效。
两个功能基本相同。
但是我对此感到不好。 recur
和完全递归的同时使用以及完全递归路径在同一函数的中间“留下”循环的感觉很奇怪,就像非结构化代码丢弃了一个好的胖GOTO。
这是供参考的表达式树:
我们离降低beta的目标还很远。只能使用显式指令流语义来理解“减少”。好的,现实符合柏拉图式的理想。
循环递归/完全递归应该看起来像这样吗?这是可以改进的样式问题吗?