【问题标题】:Why filter on a lazy sequence doesn't work in clojure?为什么过滤惰性序列在clojure中不起作用?
【发布时间】:2014-09-24 06:03:03
【问题描述】:

我希望使用以下代码生成所有小于 10 的 2 的倍数

(filter #(< % 10) (iterate (partial + 2) 2))

预期输出:

(2 4 6 8)

但是,由于某种原因,repl 没有给出任何输出?

但是,下面的代码可以正常工作...

(filter #(< % 10) '(2 4 6 8 10 12 14 16))

我知道一个是惰性序列,一个是常规序列。这就是原因。但是,如果我想从惰性序列中过滤掉所有小于 10 的数字,我该如何克服这个问题...?

【问题讨论】:

  • 有更简单的无休止的无用搜索:例如(some neg? (range))。在您的示例中,这是实现永远不会返回的第五个元素的尝试。用(take 4 ... ) 包裹你的表达式,你会得到(2 4 6 8)

标签: clojure


【解决方案1】:
(iterate (partial + 2) 2)

是一个无限序列。 filter 无法知道谓词为真的项目的数量是有限的,因此当您实现序列时它将永远持续下去(请参阅 Mark 的回答)。

你想要的是:

(take-while #(< % 10) (iterate (partial + 2) 2))

【讨论】:

    【解决方案2】:

    我想我应该注意到Diego Basch's answer 的论证并不完全正确:

    filter 无法知道谓词为真的项目的数量是有限的,所以它会一直持续下去

    为什么filter 应该对此有所了解?实际上filter 在这种情况下可以正常工作。可以将filter 应用于惰性序列并获得另一个代表可能过滤数字的无限序列的惰性序列:

    user> (def my-seq (iterate (partial + 2) 2)) ; REPL won't be able to print this
    ;; => #'user/my-seq
    user> (def filtered (filter #(< % 10) my-seq)) ; filter it without problems
    ;; => #'user/filtered
    user> 
    

    这里的关键细节是,当实际序列肯定不是有限的(因此 Clojure 知道这一点)时,永远不应该尝试实现(通过在 OP 的情况下打印)惰性序列。

    当然,这个例子只是为了演示,你应该在这里使用take-while,而不是filter

    【讨论】:

    • 完全正确。这里需要注意的是打印结果序列,这会强制实现。
    • 我同意,我应该说实现足以提供结果的序列将需要很长时间。显然(take 4 (filter ...) 会立即返回。
    猜你喜欢
    • 2011-02-26
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 2010-12-08
    相关资源
    最近更新 更多