通过将前一个项乘以常数来构建lazy-seq

时间:2013-10-28 00:37:53

标签: recursion clojure

我开始使用Clojure,尽管对递归有所了解,但我很难想出为以下函数构建一个lazy-seq的“正确”方法:

我想建立一个从中间C开始的所有频率的列表。我的第一个元素是120(中间C的频率)。为了获得第二个元素,我将第一个元素120乘以1.059463得到127.13556。为了获得第三个,我将第二个元素127.13556乘以1.059463等等......

在Clojure中最好的方法是什么?

2 个答案:

答案 0 :(得分:4)

您可以使用iterate功能。

(iterate #(* % 1.059463) 120)


如果您计划将其扩展为更复杂的东西,那么您将创建一个函数,在调用lazy-seq时递归调用自身。 (这是iterate内部的作用。)

(defn increasing-frequencies
  ([] (increasing-frequencies 120))
  ([freq]
   (cons freq (lazy-seq (increasing-frequencies (* freq 1.059463))))))

(nth (increasing-frequencies) 2) ;; => 134.69542180428002


如果你开始在紧密的循环中使用它,你可能还想生成一个分块的懒惰seq。这将预先计算下几个元素,而不是逐个计算。

(defn chunked-increasing-frequencies
  ([] (chunked-increasing-frequencies 120))
  ([freq]
   (lazy-seq
     (let [b (chunk-buffer 32)]
       (loop [i freq c 0]
         (if (< c 32)
           (do
             (chunk-append b i)
             (recur (* i 1.059463) (inc c)))
           (chunk-cons (chunk b) (chunked-increasing-frequencies i))))))))

注意:在您测量与计算单个元素相关的性能问题之前,我建议您不要这样做。

答案 1 :(得分:1)

(defn get-frequencies []
  (iterate #(* 1.059463 %) 120))

请参阅iterate

或者,如果您想明确使用lazy-seq,则可以执行以下操作:

(defn get-frequencies-hard []
  (cons
   120
   (lazy-seq
    (map #(* 1.059463 %) (get-frequencies-hard)))))  

对于应用于地图函数的每个值,cons 120将是懒惰的seq。