【问题标题】:creating a finite lazy sequence创建一个有限惰性序列
【发布时间】:2016-02-11 09:31:41
【问题描述】:

我正在使用函数iterate 创建一个惰性序列。该序列不断在每个项目上产生新值。然而,在某一时刻,产生的值“不再有意义”,因此它们毫无用处。这应该是惰性序列的结束。这是抽象形式的预期行为。

我的方法是让序列产生值。一旦检测到它们不再有用,序列只会发出 nil 值。然后,该序列将用一个 take-while 包装,使其成为有限的。

简化:

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

这可行,但这里出现了两个问题: 用 nil 作为“停止器”对有限惰性序列进行建模通常是一个好主意,还是有更好的方法?

第二个问题与我实现上述机制的方式有关,尤其是在迭代内部。 问题是:我需要一个函数来获取一个值,然后是一个谓词来测试它是否有效,如果是:in 需要传递第二个函数,否则:返回 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) 

【问题讨论】:

  • 顺便说一句:(comp not nil?) 不如(complement nil?)。 (if (mypred? (myfunction2 v)) v nil) 也可以替换为 (when (mypred? (myfunction2 v)) v)

标签: clojure functional-programming clojurescript


【解决方案1】:

用 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,序列终止。

【讨论】:

  • 感谢您的回答!我的问题是,转移到您的示例中,该 inc 必须由另一个 f 包装,例如海峡但我已经可以看出一个数字在转换为字符串之前没有通过真值测试。好吧,也许我有点忘记了这些 seq 是懒惰的,所以我可以用 (map str ..) ... 对你的整个示例进行包装......对..?
  • 没错。或者只使用(comp str inc) 代替inc。如果您需要在检查之前转换为字符串,但不希望结果中出现字符串; (comp predicate str)
【解决方案2】:

使用 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

【讨论】:

    猜你喜欢
    • 2013-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多