Clojure是否适用于无法实现惰性序列的前四个元素? [英] Clojure apply that does not realize the first four elements of a lazy sequence?

查看:58
本文介绍了Clojure是否适用于无法实现惰性序列的前四个元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

It appears that apply forces the realization of four elements given a lazy sequence.

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

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

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

Is there a way to do an apply which does not behave this way?

谢谢

推荐答案


有办法吗?做一个 apply 不会这样的行为?

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

I think the short answer is: not without reimplementing some of Clojure's basic functionality. apply's implementation relies directly on Clojure's implementation of callable functions, and tries to discover the proper arity of the given function to .invoke by enumerating the input sequence of arguments.

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

It may be easier to factor your solution using functions over lazy, un-chunked sequences / reducers / transducers, rather than using variadic functions with apply. For example, here's your sample reimplemented with transducers and it only invokes the body function once (per length of range):

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

使用 apply concat seq LazySeq ,等等:


  • 反复返回新的 LazySeq 实例:(惰性序列(cons(f)(重复为f)))

  • 对于给定2-arity (apply concat< args>) apply 调用 RT.seq 放在其参数列表中,对于 LazySeq 然后调用 LazySeq.seq ,它将调用您的函数

  • apply 然后调用Java impl。方法 applyToHelper 尝试获取参数序列的长度。 applyToHelper 尝试使用 RT.boundedLength (内部调用)确定参数列表的长度。接下来,然后依次是 seq ,因此它可以找到要正确调用 IFn.invoke 重载

  • concat 本身又增加了 lazy-seq 行为的另一层。 li>
  • repeatedly returns a new LazySeq instance: (lazy-seq (cons (f) (repeatedly f))).
  • For the given 2-arity (apply concat <args>), apply calls RT.seq on its argument list, which for a LazySeq then invokes LazySeq.seq, which will invoke your function
  • apply then calls a Java impl. method applyToHelper which tries to get the length of the argument sequence. applyToHelper tries to determine the length of the argument list using RT.boundedLength, which internally calls next and in turn seq, so it can find the proper overload of IFn.invoke to call
  • concat itself adds another layer of lazy-seq behavior.

您可以看到以下调用的堆栈跟踪:

You can see the stack traces of these invocations like this:

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

第一条轨迹来自 apply '最初对 seq 的调用,以及随后来自 RT.boundedLength 的跟踪。

The first trace descends from the apply's initial call to seq, and the subsequent traces from RT.boundedLength.

这篇关于Clojure是否适用于无法实现惰性序列的前四个元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆