Clojure是否适用于无法实现惰性序列的前四个元素?

时间:2018-08-22 03:00:05

标签: clojure

apply强制给定一个惰性序列来实现四个元素。

(take 1
      (apply concat
             (repeatedly #(do
                            (println "called")
                            (range 1 10)))))

=> "called"
=> "called"
=> "called"
=> "called"

有没有一种方法可以避免这种行为?

谢谢

2 个答案:

答案 0 :(得分:3)

  

有没有办法做这样的行为apply

我认为简短的答案是:并非不重新实现Clojure的一些基本功能。 apply的实现直接依赖于Clojure的可调用函数的实现,并通过枚举参数的输入序列来尝试发现给定函数对.invoke的正确性。

使用函数而不是无分块的序列/化简/换能器,而不是使用带有apply的可变函数来分解您的解决方案可能更容易。例如,这是使用换能器重新实现的示例,它仅调用一次body函数(每range的长度):

(sequence
  (comp
    (mapcat identity)
    (take 1))
  (repeatedly #(do
                 (println "called")
                 (range 1 10))))
;; called
;; => (1)

使用applyconcatseqLazySeq等查看示例中的情况:

  • repeatedly返回一个新的LazySeq实例:(lazy-seq (cons (f) (repeatedly f)))
  • 对于给定的2位数(apply concat <args>)apply调用其参数列表上的RT.seq,对于LazySeq,它调用LazySeq.seq,后者将调用您的功能
  • apply然后调用Java impl。方法applyToHelper尝试获取参数序列的长度。 applyToHelper尝试使用RT.boundedLength确定参数列表的长度,该内部调用next并依次调用seq,因此它可以找到要调用的proper overload of IFn.invoke
  • concat本身又增加了lazy-seq行为的另一层。

您可以看到这些调用的堆栈跟踪,如下所示:

(take 1
  (repeatedly #(do
                 (clojure.stacktrace/print-stack-trace (Exception.))
                 (range 1 10))))

第一条轨迹来自apply最初对seq的调用,随后的轨迹来自RT.boundedLength

答案 1 :(得分:0)

实际上,您的代码无法实现串联集合中的任何项(在您的情况下为范围)。因此,就元素而言,生成的集合确实是惰性的。您从函数调用中获得的打印件会生成未实现的延迟序列。可以很容易地用这种方法检查这一点:

(defn range-logged [a b]
  (lazy-seq
   (when (< a b)
     (println "realizing item" a)
     (cons a (range-logged (inc a) b)))))

user> (take 1
            (apply concat
                   (repeatedly #(do
                                  (println "called")
                                  (range-logged 1 10)))))

;;=> called
;;   called
;;   called
;;   called
;;   realizing item 1
(1)

user> (take 10
            (apply concat
                   (repeatedly #(do
                                  (println "called")
                                  (range-logged 1 10)))))
;; called
;; called
;; called
;; called
;; realizing item 1
;; realizing item 2
;; realizing item 3
;; realizing item 4
;; realizing item 5
;; realizing item 6
;; realizing item 7
;; realizing item 8
;; realizing item 9
;; realizing item 1
(1 2 3 4 5 6 7 8 9 1)

所以我的猜测是,只要repeatedly闭包返回的集合是惰性的,就不必担心