Zulip Chat Archive

Stream: lean4

Topic: Stack safe Bind


Juan Pablo Romero (Jul 17 2022 at 16:51):

Is it possible to build a stack safe Bind/Monad (a la IO) purely within Lean? or does it require special runtime support?

For example I'd like to write a stack safe function like this:

instance : Monad M where
  pure := ...
  bind := ...

def repeatN (ma: M A) (n: Nat) : M Unit := do
  let _ <- ma
  if n > 0 then
    repeatN ma (n - 1)

Henrik Böving (Jul 17 2022 at 17:05):

What do you mean by stack safe? That it doesn't kill the program in case it overflows?

Juan Pablo Romero (Jul 17 2022 at 17:07):

Yeah, I'm trying to avoid stack overflows, basically

Henrik Böving (Jul 17 2022 at 17:08):

I'd say since it depends highly on compiler optimizations if and how much stack space is used this seems quite impossible to do precisely?

Kyle Miller (Jul 17 2022 at 17:09):

I think the question here is about whether Lean does tail call optimization for monadic functions

Juan Pablo Romero (Jul 17 2022 at 17:09):

right

Chris Bailey (Jul 17 2022 at 17:10):

The CPS monads in Init.Control do (or did). You might also be able to use the loop syntax.

Juan Pablo Romero (Jul 17 2022 at 17:12):

oh, let me take a look

Sebastian Ullrich (Jul 17 2022 at 17:16):

I'd say this should just work iff your bind calls the second argument in tail position

Juan Pablo Romero (Jul 17 2022 at 17:26):

got it. In this case M is a GADT which only captures its arguments:

inductive M : Type -> Type 1 where
...
  | Bind (ma: M A) (f: A -> M B) : M B

and later gets interpreted

def run (m: M A) (callback: A -> IO Unit) : IO Unit := match m with
...
      | .Bind ma cont =>
        run ma $ fun a => run (cont a) callback
...

I guess this is where the Stack Overflow is coming.


Last updated: Dec 20 2023 at 11:08 UTC