Clojure - 无序发生的副作用

14

在学习 Clojure 的过程中,我写了一个非常基础的程序,可以将用户输入的任何内容回显。然而,它的运行方式并不像我所感知到的那样自然。以下是代码:

(defn goo []
  (print "echo> ")
  (def resp (read-line))
  (print resp)
)

我期望代码能像这样运行(当我将foo作为 read-line 的输入时):

user=> (goo)
echo> foo
foonil

但是,反而交换了回显和读取行:

user=> (goo)
foo
echo> foonil
为什么会出现这种情况?我是否漏掉了一些微妙的东西?
编辑:根据乔的答案,更新后的正确解决方案是:
(defn goo []
  (print "echo> ")
  (flush)
  (def resp (read-line))
  (print resp)
  (flush)
)

如果你使用 println 而不是 print,那么 flush 操作就不是必要的。

2个回答

18

我对Clojure一无所知,但这似乎是缓冲区未被刷新的情况。找出如何在打印后刷新标准输出。println函数可能会在每行末尾刷新。尝试使用以下代码:

(defn goo []
  (print "echo> ")
  (flush )
  (def resp (read-line))
  (print resp)
)

搞定了!在打印后添加(flush)就行了。感谢快速回复! - Chris Bunch
2
很好。现在我有一个在我不懂的语言中被核对过的答案。 :-) 很高兴能帮到你。 - jmucchiello
很好的技能!对于一个知道Clojure但不知道stdout缓冲区内部工作原理的人来说,为什么会出现这个问题呢?似乎在缓冲区内部排序会发生变化有些奇怪..... - mikera
1
我不懂Closure,所以只能猜测。内部缓冲区存在的目的是为了保持对文件系统的直接I/O量低。但是这种设计是在I/O缓慢且没有人使用线程时选择的。在面向行的终端上,只有在按下回车键时才会将数据发送到主机系统。这使得打字员可以在将其发送到主机系统之前编辑行缓冲区。人们不再使用终端,因此这种知识逐渐消失。(上周遇到一个程序员,他从未见过5.25英寸软盘....) - jmucchiello

14

此外,请不要使用 "def" ,除非您真的非常想定义一个全局变量。请使用 "let" 代替:

(defn goo []
  (print "echo> ")
  (flush)
  (let [resp (read-line)]
    (print resp)
    (flush)))
或者,更短
(defn goo []
  (print "echo> ")
  (flush)
  (print (read-line))
  (flush))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接