创建有限的懒惰序列

时间:2016-02-11 09:31:41

标签: clojure functional-programming clojurescript

我使用函数iterate创建了一个惰性序列。序列不断为每个项目生成新值。然而,在某一点上,所产生的价值并没有意义,并且#34;不再,所以他们没用。这应该是懒惰序列的结束。这是抽象形式的预期行为。

我的方法是让序列产生值。一旦检测到它们不再有用,序列将只发出零值。然后,序列将被包裹起来,以使其有限。

简化为:

(take-while (comp not nil?)
   (iterate #(let [v (myfunction1 %)]
                (if (mypred? (myfunction2 v)) v nil)) start-value))

这有效,但这里出现两个问题: 用nil作为"塞子"来模拟有限的懒惰序列通常是个好主意,还是有更好的方法?

第二个问题与我实现上述机制的方式有关,特别是在迭代内部。 问题是:我需要一个函数来获取一个值,然后一个谓词来测试它是否有效,如果是:需要传递第二个函数,否则:返回nil。 我正在寻找一种不那么迫切的方式来实现这一点,更具体地省略了let语句。相反,像这样:

(defn pass-if-true [pred v f]
   (when (pred? v) (f v)))

#(pass-if-true mypred? (myfunction1 %) myfunction2)

现在,我将继续这样做:

(comp #(when (mypred? %) (myfunction2 %)) myfunction1) 

2 个答案:

答案 0 :(得分:3)

  

用nil作为“塞子”对有限懒惰序列进行建模通常是个好主意,还是有更好的方法?

nil是结束有限懒惰序列的惯用方法。

关于第二个问题,请尝试这样写:

(def predicate (partial > 10))
(take-while predicate (iterate inc 0))
;; => (0 1 2 3 4 5 6 7 8 9)

此处inc采用先前的值并生成下一个值,predicate测试值是否良好。第一次predicate返回false时,序列终止。

答案 1 :(得分:0)

使用nil的返回值可以使惰性序列终止。

例如,此代码计算两个整数的最大公约数:

(defn remainder-sequence [n d]
  (let [[q r] ((juxt quot rem) n d)]
    (if (= r 0) nil
        (lazy-seq (cons r (remainder-sequence d r))))))

(defn gcd [n d]
  (cond (< (Math/abs n) (Math/abs d)) (gcd d n)
        (= 0 (rem n d)) d
        :default (last (remainder-sequence n d))))

(gcd 100 32) ; returns 4