在没有完全重新实现函数的情况下更改递归函数契约?

时间:2012-04-01 01:53:17

标签: binding clojure

我想更改以下Quicksort实现的契约,以返回执行排序操作所需的递归调用次数。

来源:http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Clojure

(defn qsort [[pivot & xs]]
  (when pivot
    (let [smaller #(< % pivot)]
      (lazy-cat (qsort (filter smaller xs))
                [pivot]
        (qsort (remove smaller xs))))))

我想要做的是实现内部使用上述qsort实现的counted-qsort

我正在寻找一个如何做到这一点的例子。我怀疑可能涉及(bind ...)

1 个答案:

答案 0 :(得分:5)

我在这个问题上玩了一会儿,这就是我想出的:

(defn counted-qsort [coll]
  (let [count (atom 0) qs qsort]
    (with-redefs [qsort (fn [coll]
                          (swap! count inc)
                          (prn coll)
                          (qs coll))]
      (dorun (qsort coll)))
    (deref count)))

此函数暂时重新定义qsort,以便它可以管理一个原子,该原子包含最终调用qsort次数的计数。 let绑定中的qs允许在重新定义的版本中引用原始qsort函数,以避免无限递归。

我使用“count”而不是“depth”,因为我不确定“depth”是否正确使用。此函数计算调用qsort的次数,而不是“树”的实际深度。

我不知道用这种方法是否可以保持懒惰。

使用prn进行调试的示例输出:

[1 2 3]
()
(2 3)
()
(3)
()
()
7 ;return value

我假设Clojure 1.3并且qsort已在同一名称空间中定义。