Zulip Chat Archive

Stream: lean4

Topic: timeout at 'whnf' in forallTelescope


Floris van Doorn (Jan 20 2022 at 14:54):

I get the following error when running forallTelescope.

uncaught exception: (deterministic) timeout at 'whnf', maximum number of heartbeats (50000) has been reached (use 'set_option maxHeartbeats <num>' to set the limit)

I am a bit confused about this, I thought that forallTelescope doesn't reduce the expression at all, as opposed to forallTelescopeReducing.

I can reproduce this when I run forallTelescope on all declarations of mathlib3port (current commit - 9b3a383). Here is my code:

import Lean

open Lean Meta Core
-- you need to clone and `lake build` mathlib3port in the right directory to run this
def main (strs : List String) : IO UInt32 := do
  let env  do
    initSearchPath ( Lean.findSysroot?) ["../mathlib3port/build/lib",
      "../mathlib3port/lean_packages/lean3port/build/lib/",
      "../mathlib3port/lean_packages/mathlib/build/lib/"]
    importModules [{module := `Mathbin}] {}
  let _  CoreM.toIO (MetaM.run' do
    let decls  ( getEnv).constants.map₁.toArray.map (·.1)
    decls.forM λ nm => if !nm.isInternal then do
      let info  getConstInfo nm
      let isprop  forallTelescope info.type $ λ _ e => e.isProp
      IO.println s!"{nm}: {isprop}"
    else return ()
    ) {} {env := env}
  return 0

Note: when I replace forallTelescope by a structural recursion on the expression, I don't get an error.

import Lean

open Lean Meta Core

namespace Lean.Expr

def piCodomain : Expr  Expr
| forallE n t b d => piCodomain b
| e => e

end Lean.Expr


def main (strs : List String) : IO UInt32 := do
  let env  do
    initSearchPath ( Lean.findSysroot?) ["../mathlib3port/build/lib",
      "../mathlib3port/lean_packages/lean3port/build/lib/",
      "../mathlib3port/lean_packages/mathlib/build/lib/"]
    importModules [{module := `Mathbin}] {}
  let _  CoreM.toIO (MetaM.run' do
    let decls  ( getEnv).constants.map₁.toArray.map (·.1)
    decls.forM λ nm => if !nm.isInternal then do
      let info  getConstInfo nm
      let isprop  info.type.piCodomain.isProp
      IO.println s!"{nm}: {isprop}"
    else return ()
    ) {} {env := env}
  return 0

Is this the expected behavior (for complicated enough expressions)?

Sebastian Ullrich (Jan 20 2022 at 15:06):

forallTelescope may need to reduce domains to check for type classes. Which should be cheap, but it might accumulate.

Sebastian Ullrich (Jan 20 2022 at 15:08):

The heartbeat limit is mostly for interactive use, you can set it to some higher number (or 0) in the CoreM.toIO call

Floris van Doorn (Jan 20 2022 at 15:21):

Thanks! Both of those options indeed solve the problem.
I didn't know that the number of heartbeats was for the whole CoreM.toIO call instead of each whnf call individually.

Sebastian Ullrich (Jan 20 2022 at 15:23):

I believe it's because whnf is regarded as a helper function to be used in larger modules that define a "heartbeat scope". For example TC resolution is a scope.


Last updated: Dec 20 2023 at 11:08 UTC