Zulip Chat Archive
Stream: lean4
Topic: Weird IO Behavior Introduced in v4.12.0
Kaiyu Yang (Oct 13 2024 at 17:01):
Hi,
LeanDojo has been broken starting from Lean v4.12.0. After some debugging, I reduced the problem to the following minimal working example:
import Lean.Elab.Tactic
elab "echo" : tactic => do
while true do
println! "Hello!"
(← IO.getStdout).flush
let line := (← (← IO.getStdin).getLine).trim
println! s!"`{line}`"
if line == "bye" then
break
example : 1 = 1 := by
echo
sorry
When running it with leanprover/lean4:v4.11.0
, I got the expected behavior (screenshot below): It prints Hello
and waits for the user input. It echos the user input until the user enters bye
.
image.png
However, the program hangs starting from leanprover/lean4:v4.12.0
:
image.png
I really appreciate any help! Thanks!
Henrik Böving (Oct 13 2024 at 17:16):
def main : IO Unit := do
while true do
IO.println "Hello!"
(← IO.getStdout).flush
let line := (← (← IO.getStdin).getLine).trim
IO.println s!"`{line}`"
if line == "bye" then
break
return ()
running this one with lean --run
works so this is most likely related to the way that stdin and out are setup when you are in an elaboration context. @Sebastian Ullrich should have the details on this in his cache.
Sebastian Ullrich (Oct 13 2024 at 17:33):
I'm afraid this is not a robust approach, it will only be broken further by elaboration parallelism
Sebastian Ullrich (Oct 13 2024 at 17:35):
External interaction must drive elaboration like in the repl, not the other way around
Kaiyu Yang (Oct 13 2024 at 18:53):
@Sebastian Ullrich Thanks! Does that mean I/O in TacticM may lead to undefined behaviors (if so, we probably shouldn't have instances of MonadLift IO TacticM
)? In general, I'm wondering why it is not advisable for elaboration to drive external interactions, and how this is impacted by elaboration parallelism.
Henrik Böving (Oct 13 2024 at 18:54):
No, the key issue here is that you are interacting with stdin, it would e.g. be perfectly fine to read a file that contains a proof generated by an external tool from an elaborator
Kaiyu Yang (Oct 13 2024 at 18:57):
In this context, how is reading from stdin different from a file?
Henrik Böving (Oct 13 2024 at 19:00):
Things that run in the elaboration context do not actually get to play with the true process stdin anymore.
Sebastian Ullrich (Oct 13 2024 at 19:01):
Stdin is shared mutable state while opening a file temporarily for reading is usually a very scoped operation (if you did read from the same file you're writing to in another declaration's elaboration that wouldn't be great either, no)
Kaiyu Yang (Oct 13 2024 at 19:24):
In my use case, it is guaranteed that only one declaration interacts with stdin during elaboration, so shared mutable state may not be a real problem. Is it possible to guard stdin with something like a mutex?
Last updated: May 02 2025 at 03:31 UTC