Zulip Chat Archive

Stream: lean4

Topic: Qq reduceEval: failed to evaluate argument n


Kenny Lau (Aug 11 2025 at 16:00):

import Qq

open Lean Expr Qq

def Nat.mkLiteralQ (n : Nat) : Q(Nat) :=
  have enlit : Q(Nat) := mkRawNatLit n
  q(OfNat.ofNat $enlit)

elab "check_nat%" nStx:num : term =>
  return nStx.getNat.mkLiteralQ
#check 0
#check check_nat% 0
#check 1
#check check_nat% 1
#check 37
#check check_nat% 37

namespace Qq

/-- Given `en : Q(Nat)`, return optionally a natural number `n` and a witness that `en` is defeq
to `OfNat.ofNat (natlit $n)`. -/
def natQ? (en : Q(Nat)) : Option { n : Nat // $en =Q $(n.mkLiteralQ) } :=
  en.nat?.map fun n  n, ⟨⟩⟩

end Qq
set_option pp.rawOnError true
/-- Interpret a given `e : Expr` as a vector `v : Fin n → Nat`. -/
def test (e : Expr) : MetaM ((n : Nat) × Q(Fin $n  Nat)) := do
  let 1, ~q(Fin $en  Nat), v  inferTypeQ e
    | throwError "Invalid input: cannot decompose into Fin n → Nat"
  let .some n := natQ? en
    | throwError "The length of the vector is not determined"
  let n, _⟩ := n
  let en' : Q(Nat) := n.mkLiteralQ
  have v' : Q(Fin $en'  Nat) := q($v)
  return n, v'

Kenny Lau (Aug 11 2025 at 16:00):

I find it slightly difficult to work with Qq, because sometimes the expected type window just stops loading, and I get strange error messages

Kenny Lau (Aug 11 2025 at 16:01):

e.g. in the code above, on Line 23 the expected type window just fails with error "Error updating: Error fetching goals: Rpc error: InternalError: failed. Try again."

on Line 33 I see the same error, and then Line 34 just stops compiling. What did I do wrong?

Aaron Liu (Aug 11 2025 at 16:02):

Qq is very picky about what you let and what you have

Aaron Liu (Aug 11 2025 at 16:02):

Only let something Qq if Qq can recognize the contents

Kenny Lau (Aug 11 2025 at 16:02):

changing those lets to haves or vice versa doesn't solve anything

Kenny Lau (Aug 11 2025 at 16:03):

oh btw #check natQ? on L24 is also error

Kenny Lau (Aug 11 2025 at 16:03):

How should I fix this?

Aaron Liu (Aug 11 2025 at 16:05):

The problem is the type of natQ?

Aaron Liu (Aug 11 2025 at 16:05):

Qq can't recognize Nat.mkLiteralQ

Aaron Liu (Aug 11 2025 at 16:12):

or maybe it can't do the n in the subtype formula, based on the error message

Aaron Liu (Aug 11 2025 at 16:12):

you will have better luck doing

def natQ? (en : Q(Nat)) :
    Option { n : Nat //
      have k := n.mkLiteralQ
      $en =Q $k } :=

Kenny Lau (Aug 11 2025 at 16:14):

yeah but then i can't use it afterwards anyway

Kenny Lau (Aug 11 2025 at 16:14):

like it seems like q($n) is just bad

Kenny Lau (Aug 11 2025 at 16:19):

import Qq

open Lean Expr Qq

def Nat.mkLiteralQ (n : Nat) : Q(Nat) :=
  have enlit : Q(Nat) := mkRawNatLit n
  q(OfNat.ofNat $enlit)

elab "check_nat%" nStx:num : term =>
  return nStx.getNat.mkLiteralQ
#check 0
#check check_nat% 0
#check 1
#check check_nat% 1
#check 37
#check check_nat% 37

namespace Qq

/-- Given `en : Q(Nat)`, return optionally a natural number `n` and a witness that `en` is defeq
to `OfNat.ofNat (natlit $n)`. -/
def natQ? (en : Q(Nat)) : Option { n : Nat //
    have en' : Q(Nat) := n.mkLiteralQ
    $en =Q $en' } :=
  en.nat?.map fun n  n, ⟨⟩⟩

end Qq
set_option pp.rawOnError true
/-- Interpret a given `e : Expr` as a vector `v : Fin n → Nat`. -/
def test (e : Expr) : MetaM ((n : Nat) × Q(Fin $n  Nat)) := do
  let 1, ~q(Fin $en  Nat), v  inferTypeQ e
    | throwError "Invalid input: cannot decompose into Fin n → Nat"
  let .some n, _⟩ := natQ? en
    | throwError "The length of the vector is not determined"
  have en' : Q(Nat) := n.mkLiteralQ
  -- have v' : Q(Fin $en' → Nat) := q($v)
  return n, v'

Kenny Lau (Aug 11 2025 at 16:19):

This still errors

Kenny Lau (Aug 11 2025 at 16:24):

is there a better way to use Nat in Qq?

Aaron Liu (Aug 11 2025 at 16:24):

just do $n maybe

Aaron Liu (Aug 11 2025 at 16:24):

Don't know if that will work though

Kenny Lau (Aug 11 2025 at 16:25):

$n also causes errors

Kenny Lau (Aug 11 2025 at 16:25):

sometimes

Kenny Lau (Aug 11 2025 at 16:25):

it's very unpredictable (for a noob like me)

Aaron Liu (Aug 11 2025 at 16:26):

it's unpredictable for me too

Kenny Lau (Aug 11 2025 at 16:28):

mwe:

import Qq

open Lean Expr Qq

/-- Interpret a given `e : Expr` as a vector `v : Fin n → Nat`. -/
def test (e : Expr) : MetaM ((n : Nat) × Q(Fin $n  Nat)) := do
  let 1, ~q(Fin $en  Nat), v  inferTypeQ e
    | throwError "Invalid input: cannot decompose into Fin n → Nat"
  let .some n := en.nat?
    | throwError "The length of the vector is not determined"
  -- have : $en =Q $n := ⟨⟩
  have v' : Q(Fin $n  Nat) := q($v)
  return n, v'

Kenny Lau (Aug 11 2025 at 16:28):

Note that the code errors at $v (L12), and if you look at the context you'll see that it's missing the line L11 commented out above, and if you remove the comment then you get another error

Kenny Lau (Aug 11 2025 at 16:30):

the longer code is when i tried to provide API for nat?

Wuyang (Aug 11 2025 at 16:34):

working with Qq and Nat literals can be tricky... or avoiding q($n) where possible could help.

Also, you might find related tricks in LeanFinder (www.leanfinder.org).

Wuyang (Aug 11 2025 at 16:34):

@leanfinder How to correctly quote and unquote Nat values in Lean 4 Qq without type errors when using mkLiteralQ, nat?, and subtype witnesses inside macros or MetaM functions

leanfinder (Aug 11 2025 at 16:34):

Here’s what I found:

  • [definition Mathlib.Meta.NormNum.mkOfNat(α : Q(Type u)) (_sα : Q(AddMonoidWithOne $α)) (lit : Q(ℕ)) :
    MetaM ((a' : Q($α)) × Q($lit = $a')) := do
    if α.isConstOf Nat then let a' : Q(ℕ) := q(OfNat.ofNat $lit : ℕ) pure ⟨a', (q(Eq.refl $a') : Expr)⟩ else if α.isConstOf Int then
    let a' : Q(ℤ) := q(OfNat.ofNat $lit : ℤ)
    pure ⟨a', (q(Eq.refl $a') : Expr)⟩
    else if α.isConstOf `Rat then let a' : Q(ℚ) := q(OfNat.ofNat $lit : ℚ) pure ⟨a', (q(Eq.refl $a') : Expr)⟩ else let some n := lit.rawNatLit? | failure match n with | 0 => pure ⟨q(0 : $α), (q(Nat.cast_zero (R := $α)) : Expr)⟩ | 1 => pure ⟨q(1 : $α), (q(Nat.cast_one (R := $α)) : Expr)⟩ | k+2 => let k : Q(ℕ) := mkRawNatLit k let _x : Q(Nat.AtLeastTwo $lit) := (q(instNatAtLeastTwo (n := $k)) : Expr) let a' : Q($α) := q(OfNat.ofNat $lit) pure ⟨a', (q(Eq.refl $a') : Expr)⟩](https://leanprover-community.github.io/mathlib4_docs/find/?pattern=Mathlib.Meta.NormNum.mkOfNat#doc) "Given a type $$\alpha$$ with an AddMonoidWithOne instance and a natural number literal lit, this function constructs an expression a' of type $$\alpha$$ representing the canonical interpretation of lit in $$\alpha$$, along with a proof that lit equals a'. The function handles special cases for $$\alpha$$ being Nat, Int, or Rat directly for efficiency, and falls back to general Nat.cast` for other types." (score: 0.700)

  • definition Mathlib.Tactic.AtomM.addAtomQ{u : Level} {α : Q(Type u)} (e : Q($α)) : AtomM (Nat × {e' : Q($α) // $e =Q $e'}) := do let (n, e') ← AtomM.addAtom e return (n, ⟨e', ⟨⟩⟩) "Given an atomic expression e of type α, this function checks if e has been previously encountered (up to definitional equality at the specified transparency level). If it has, it returns the index of the stored version and the stored expression (which is definitionally equal to e). If not, it stores e in the list of atoms and returns its new index along with e itself. The returned expression should be considered the normal form in a normalizing tactic.

This is a strongly-typed version using Qq (quoted expressions) that ensures type safety by maintaining a proof that the returned expression e' is definitionally equal to the input e." (score: 0.695)

  1. A quoted natural number expression m : Q(ℕ) representing the absolute value of n
  2. A proof that the integer absolute value of n equals m (i.e., Q(Int.natAbs $$n = $$m))

The function handles both positive integers (constructed via Int.ofNat) and negative integers (constructed via Int.negOfNat), returning their absolute values with corresponding proofs." (score: 0.677)

  1. The natural number literal lit being cast
  2. A proof that e is equal to the coercion of lit into α (i.e., IsNat e lit holds)" (score: 0.676)

Kenny Lau (Aug 11 2025 at 16:40):

I'm not sure if any of these results are relevant

Kim Morrison (Aug 12 2025 at 02:14):

Yeah, hopefully @Wuyang has learnt that this was really spammy and unhelpful to summon LeanFinder in so many places. :-(


Last updated: Dec 20 2025 at 21:32 UTC