Zulip Chat Archive

Stream: general

Topic: fully reduce type


Mirek Olšák (Feb 21 2026 at 09:47):

In a lecture, I would like to show an example of the type

import Mathlib

def iteratePow (n : ) : Type :=
  match n with
  | 0 => 
  | k+1 => (iteratePow k)  Prop

to give an idea of how easily a large type can be build. However, I would also like to show how this actually evaluates. Naturally #eval doesn't work. I hoped #reduce could do it but it refuses to reduce the term fully, leaving some mess of Nat.rec

#eval iteratePow 3 -- error
#reduce (types := true) iteratePow 3 -- mess

The best I have come up with so far is

#simp [iteratePow] => iteratePow 3 -- ((ℕ → Prop) → Prop) → Prop

but it is quite high level, and somewhat inaccurate description of what is happening when Lean accepts say

example : iteratePow 1 := fun n : Nat  n > 5

Is there any way of actually reducing the expression iteratePow 3? Say in tactic mode? Or using meta-code if there is no better option?

Jovan Gerbscheid (Feb 21 2026 at 10:16):

Huh, that's wierd, looking at the implementation of docs#Lean.Meta.reduce, we see that it doesn't actually reduce in the domain of a forall. I'm afraid you'll have to implement your own version, and you can copy-paste docs#Lean.Elab.Command.elabReduce

Mirek Olšák (Feb 21 2026 at 11:07):

If I need modify the code Meta.reduce for this, what is the correct way of reducing type in a LocalDecl?

Jovan Gerbscheid (Feb 21 2026 at 11:26):

Here's a neat way to implement a fully reducing version of reduce:

import Lean

open Lean Meta Elab Command

def fullReduce (e : Expr) : MetaM Expr := do
  transform e (pre := fun e  return .continue ( whnf e))

-- copied elaborator for `#reduce` command
@[command_elab Lean.reduceCmd] def elabReduce : CommandElab
  | `(#reduce%$tk $term) => go tk term
  | _ => throwUnsupportedSyntax
where
  go (tk : Syntax) (term : Syntax) : CommandElabM Unit :=
    withoutModifyingEnv <| runTermElabM fun _ => Term.withDeclName `_reduce do
      let e  Term.elabTerm term none
      Term.synthesizeSyntheticMVarsNoPostponing
      -- Users might be testing out buggy elaborators. Let's typecheck before proceeding:
      withRef tk <| Meta.check e
      let e  Term.levelMVarToParam ( instantiateMVars e)
      -- TODO: add options or notation for setting the following parameters
      withTheReader Core.Context (fun ctx => { ctx with options := ctx.options.set `smartUnfolding false }) do
        let e  withTransparency (mode := TransparencyMode.all) <| fullReduce e
        logInfoAt tk e

def iteratePow (n : Nat) : Type :=
  match n with
  | 0 => Nat
  | k+1 => (iteratePow k)  Prop

#reduce iteratePow 3 -- expected result

Mirek Olšák (Feb 21 2026 at 21:06):

Thanks, the transform might be not super-efficient but completely sufficient for my needs. I also simplified the elab part, and call it #full_reduce, in my materials.


Last updated: Feb 28 2026 at 14:05 UTC