Zulip Chat Archive

Stream: new members

Topic: Step by step logging in main


Thomas Vigouroux (Aug 06 2024 at 08:39):

Hey there,

I would like to have a main function that does:

def main: IO Unit := do
  IO.println "Before a"
  let a := fa args
  IO.println "After a"

When I do that in lean (assume we wait a few seconds in fa args), the text is all printed at once at the very end of the execution.

Do I have a way to "force" the execution to be step-by-step ?

Henrik Böving (Aug 06 2024 at 08:40):

That's not the case, if you run the binary that is generated from this code the IO will happen "step by step" and not at once in the end

Thomas Vigouroux (Aug 06 2024 at 08:41):

Oh I guess I was not clear.
My problem is that (looking at the binary), lean computes fa args during initialization of the binary, and then executes the body on the function.

I'd like to force fa args being computed in order, instead of at initialization

Henrik Böving (Aug 06 2024 at 08:43):

you can disable closed term extraction with set_option compiler.extract_closed false

Thomas Vigouroux (Aug 06 2024 at 08:44):

That worked, thank you very much !

Thomas Vigouroux (Aug 06 2024 at 09:07):

One last question while we're at it.
I have a monad to which I want to add an IO effect, is there an easy way to do so ?

Thomas Vigouroux (Aug 06 2024 at 09:13):

Basically I have a monad that I use to make a computation and I'd like to have a step where I print stuff to the screen in between computations

Henrik Böving (Aug 06 2024 at 09:23):

Do you know about monad transformers?

Thomas Vigouroux (Aug 06 2024 at 09:23):

Kind of, I'm reading the "Functionnal programming in Lean" about that ;-)

Thomas Vigouroux (Aug 06 2024 at 09:23):

But I can't find an IO transformer

Henrik Böving (Aug 06 2024 at 09:23):

That's what you want to use^^

Henrik Böving (Aug 06 2024 at 09:23):

Right

Henrik Böving (Aug 06 2024 at 09:24):

IO does not have a transformer, you would usually write your monad like ReaderT SomeContext <| StateT SomeState IO so IO would always be at the bottom of your monad stack.

Eric Wieser (Aug 06 2024 at 10:56):

If working over a general monad, you can use [MonadLiftT IO m], right?

Thomas Vigouroux (Aug 06 2024 at 12:00):

Actually let me add a little more context.
My goal is to prove of disprove that each turing machine in a set terminates.
My way into that is to have "deciders" which are algorithms which try to prove that the machine halts (or loops forever).

My idea was to have a monad like that, in order to chain deciders:

inductive HaltM (M: Machine) (α: Type u)
| unknown: α  HaltM M α
| halts_prf : M.halts  HaltM M α
| loops_prf : ¬M.halts  HaltM M α

Then if my decider has the type Unit -> HaltM M Unit I can chain them to have a bigger decider that tries them all, right ?

Thomas Vigouroux (Aug 06 2024 at 12:03):

Conveniently, stepping a machine can also give me an instance of this monad, that gives me either the next state in .unknown or the proof that the machine halts (we reached a halting state)

def Machine.step (M: Machine) (C: Config): HaltM M Config := ...

Thomas Vigouroux (Aug 06 2024 at 12:04):

Now let's say I want to extend my deciders to allow them to print stuff on the screen, what would their return type be ?

I can't see if it is IO (HaltM ...) or some kind of other thing

Thomas Vigouroux (Aug 06 2024 at 12:20):

In particular, I have a decider that looks somewhat like this:

def looperDec (M: Machine) (init: Config) : IO (HaltM M Unit) := do
      let state1: Config := (M.step init >>= M.step)
      let state2: Config := M.step init
      ...

But I get the following error:

type mismatch
  M.step init >>= M.step
has type
  HaltM M Config : Type
but is expected to have type
  Config : Type

Last updated: May 02 2025 at 03:31 UTC