下面的代码是创建我没想到的输出。
(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上没有产生输出。这是为什么?
答案 0 :(得分:0)
REPL得到它的三个阶段的名称:Read,Eval,Print Loop。
my-rand
只返回整数。
repl隐式打印结果(来自repeatedly
的结果列表)。同时my-rand中的println
语句产生它们的输出。交错发生是因为除非你实现某种锁定,否则多个函数的输出是不可预测的,并且没有保证的顺序。
答案 1 :(得分:0)
take
和repeatedly
都会产生延迟序列。因此,(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”。但是,对于后续元素,已经实现了“当前”元素以便打印“前一个”元素,因此此时只需要实现“下一个”元素(如果有的话)。