I'm new to Clojure, and am trying to redirect output to a file by rebinding *out*. In a simple case, it works nicely:
(binding [*out* (new java.io.FileWriter "test.txt")]
(println "Hi"))
This does what I expect, printing "Hi" to the file test.txt. However, if I introduce a for loop, things go awry:
(binding [*out* (new java.io.FileWriter "test.txt")]
(for [x [1 2]]
(println "Hi" x)))
This time, all the output goes to stdout, and the file is empty. What's going on here?
I'm using Leiningen, if that makes any difference:
Leiningen 2.0.0 on Java 1.7.0_13 Java HotSpot(TM) 64-Bit Server VM
you have been bitten by the lazy bug.
put a doall or dorun around the for and within the binding
(binding [*out* (new java.io.FileWriter "test.txt")]
(doall (for [x [1 2]]
(println "Hi" x))))
In your example the printing is happening then the result is printed by the repl after it is returned from the binding. So at the time of printing the binding is no longer in place.
Nothing is printed because result is a lazy sequence that will later be evaluated when used
user> (def result (binding [*out* (new java.io.FileWriter "test.txt")]
(for [x [1 2]]
(println "Hi" x))))
#'user/result
When the repl prints the resuls the printlns are evaluated:
user> result
(Hi 1
Hi 2
nil nil)
If we force the evaluation of the lazy sequence returned by for within the binding
nothing is printed to the repl,
user> (def result (binding [*out* (new java.io.FileWriter "test.txt")]
(doall (for [x [1 2]]
(println "Hi" x)))))
#'user/result
user> result
(nil nil)
and instead the output ends up in the file:
arthur@a:~/hello$ cat test.txt
Hi 1
Hi 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With