Zulip Chat Archive

Stream: lean4

Topic: Difference in behaviour between Kernel.whnf and whnf


Yann Herklotz (Sep 27 2024 at 15:51):

In the following, it seems like Kernel.whnf gets stuck and doesn't reduce the instance for Nat of ToString (instToStringNat) and the result therefore isn't in whnf form. whnf on the other hand reduces it fine.

import Lean
open Lean Meta Elab
#eval show Term.TermElabM Unit from do
  let expr  (Term.elabTerm ( `(toString (1 : Nat))) none)
  let res  Lean.ofExceptKernelException <| Kernel.whnf ( getEnv) {} expr
  -- let res ← whnf expr
  Lean.logInfo m!"{res}"

Is this behaviour/difference expected?

I'm a bit surprised that the following works though, meaning the kernel can type check the following and the Kernel.isDefEq can at least look through toString and the instance. This suggests that Kernel.isDefEq might not use Kernel.whnf.

example : toString (1 : Nat) = "1" := by rfl

There is a comment saying that Kernel.whnf is mostly available for debugging, but it has been useful for us to reduce terms much more efficiently. Should it not be relied on?

Mario Carneiro (Sep 28 2024 at 00:21):

If you print the full expression expr you will see it has instantiated mvars:

#eval show Term.TermElabM Unit from do
  let expr  (Term.elabTerm ( `(toString (1 : Nat))) none)
  Lean.logInfo m!"{repr expr}"
-- Lean.Expr.app
--   (Lean.Expr.app
--     (Lean.Expr.app
--       (Lean.Expr.const `ToString.toString [Lean.Level.mvar (Lean.Name.mkNum `_uniq 1)])
--       (Lean.Expr.mvar (Lean.Name.mkNum `_uniq 2)))
--     (Lean.Expr.mvar (Lean.Name.mkNum `_uniq 3)))
--   (Lean.Expr.app
--     (Lean.Expr.app
--       (Lean.Expr.app (Lean.Expr.const `OfNat.ofNat [Lean.Level.zero]) (Lean.Expr.mvar (Lean.Name.mkNum `_uniq 6)))
--       (Lean.Expr.lit (Lean.Literal.natVal 1)))
--     (Lean.Expr.mvar (Lean.Name.mkNum `_uniq 7)))

You need to call instantiateMVars to get rid of these mvars.

#eval show Term.TermElabM Unit from do
  let expr  (Term.elabTerm ( `(toString (1 : Nat))) none)
  let expr  instantiateMVars expr
  let expr  Lean.ofExceptKernelException <| Kernel.whnf ( getEnv) {} expr
  Lean.logInfo m!"{expr}"
  -- { data := Nat.toDigits 10 1 }

Kyle Miller (Sep 28 2024 at 00:23):

Just to be safe, probably should synthesize pending metavariables too.

#eval show Term.TermElabM Unit from do
  let expr  (Term.elabTerm ( `(toString (1 : Nat))) none)
  Term.synthesizeSyntheticMVarsUsingDefault
  let expr  instantiateMVars expr
  let expr  Lean.ofExceptKernelException <| Kernel.whnf ( getEnv) {} expr
  Lean.logInfo m!"{expr}"

Yann Herklotz (Sep 28 2024 at 11:10):

Ahh thank you! I need to be more careful with checking for mvars in the expression.


Last updated: May 02 2025 at 03:31 UTC