为什么过滤懒惰序列在clojure中不起作用?

cel*_*tas 6 clojure

我希望使用以下代码生成小于10的两个倍数

(filter #(< % 10) (iterate (partial + 2) 2))
Run Code Online (Sandbox Code Playgroud)

预期产量:

(2 4 6 8)
Run Code Online (Sandbox Code Playgroud)

但是,出于某种原因,repl只是不提供任何输出?

但是,下面的代码工作得很好......

(filter #(< % 10) '(2 4 6 8 10 12 14 16))
Run Code Online (Sandbox Code Playgroud)

我知道一个是懒惰序列,一个是常规序列.这就是原因.但是如果我希望从懒惰序列中过滤掉所有小于10的数字,我怎么能克服这个问题呢?

Die*_*sch 9

(iterate (partial + 2) 2)
Run Code Online (Sandbox Code Playgroud)

是一个无限的序列.filter无法知道谓词为真的项目数是有限的,所以当你意识到序列时它将永远存在(参见Mark的回答).

你想要的是:

(take-while #(< % 10) (iterate (partial + 2) 2))
Run Code Online (Sandbox Code Playgroud)


Mar*_*ark 5

我想我应该注意到Diego Basch的答案在其论证中并不完全正确:

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> 
Run Code Online (Sandbox Code Playgroud)

这里的关键细节是,当实际序列不确定时(因此Clojure知道这一点),人们不应该试图实现(通过在OP的情况下打印)延迟序列.

当然,这个例子仅用于演示目的,你应该take-while在这里使用,而不是filter.

  • 究竟.这里需要注意的是打印生成的序列,这会强制实现. (2认同)