我正在反复进行bizzaro行为并且在clojure中打印出来

时间:2013-12-28 04:19:57

标签: java clojure

下面的代码是创建我没想到的输出。

(defn my-rand []
  (let [r (rand-int 10)]
    (print "HI ")
    r)) 

(take 3 (repeatedly #(my-rand))) -> (HI HI 5 HI 5 4)
(take 4 (repeatedly #(my-rand))) -> (HI HI 7 HI 0 HI 2 9)
(take 5 (repeatedly #(my-rand))) -> (HI HI 4 HI 2 HI 4 HI 3 2)
(take 6 (repeatedly #(my-rand))) -> (HI HI 7 HI 6 HI 5 HI 6 HI 2 6)

(my-rand) -> 7 | stdout: HI

我发现奇怪的是take ... repeatedly产生了两个连续的“HI”。我还注意到最后生产的两件物品都是r。另外,有趣的是,take ... repeatedly调用在stdout上没有产生输出。这是为什么?

2 个答案:

答案 0 :(得分:0)

REPL得到它的三个阶段的名称:Read,Eval,Print Loop。

my-rand只返回整数。

repl隐式打印结果(来自repeatedly的结果列表)。同时my-rand中的println语句产生它们的输出。交错发生是因为除非你实现某种锁定,否则多个函数的输出是不可预测的,并且没有保证的顺序。

答案 1 :(得分:0)

takerepeatedly都会产生延迟序列。因此,(take 3 (repeatedly my-rand))将不会调用my-rand,除非并且当序列被实现时(即,遍历它时)。因此,如果您从未对生成的seq执行任何操作,则不会在stdout上看到任何内容。

正如noisesmith所指出的,如果你在REPL中,REPL将打印你给它的表达式返回的值。在这个花瓶中,(take 3 (repeatedly my-rand))将产生一个未实现的懒惰seq。然后REPL将打印该seq。 print函数遍历seq,并且稍加格式化,打印seq的每个元素。由于seq之前未实现过,因此需要在打印之前实现这些元素。现在实现一个元素意味着调用my-rand,然后调用print。因此,print内的my-rand次调用与每个元素的打印交错。

鉴于我们有一个懒惰的seq,我可以看到为什么看到两个“HI”连续打印会令人惊讶。毕竟(假设之前没有实现任何元素),由于元素一次打印一个,我们不应该在每个元素之前看到一个“HI”吗?由于amalloy在评论noisesmith的答案时暗示,为了确定惰性seq是否具有下一个元素,必须实现下一个元素(如果存在)。显然,在打印当前元素之前进行该确定。结果,在打印第一个元素之前实现前两个元素。因此两个“HI”。但是,对于后续元素,已经实现了“当前”元素以便打印“前一个”元素,因此此时只需要实现“下一个”元素(如果有的话)。