Zulip Chat Archive

Stream: lean4

Topic: Type mismatch with Qq library


Heather Macbeth (Aug 24 2024 at 22:55):

Suppose I wanted to parse an expression of the form (a + (b + c)) + d into a list [a, b, c, d] (this is a simplified problem but I can #xy if needed). Here is my quick attempt to do this with quote4:

import Qq

open Lean Qq

def parse {v : Level} (M : Q(Type v)) (x : Q($M)) : MetaM (Q(List $M)) := do
  match x with
  | ~q(@HAdd.hAdd $N $N $N _ $x $y) =>
    let .defEq (_ : $M =Q $N)  isDefEqQ M N | throwError "FIXME let's deal with this later"
    let a : Q(List $M)  parse M x
    let b : Q(List $M)  parse M y
    pure q($a ++ $b)
  | e => pure q([$e])

This produces the following error:

type mismatch
  ?m + ?m✝¹
has type
  ?m : Type ?u.370
but is expected to have type
  «$M» : Type v

Can someone explain this error? What am I doing wrong?

Mario Carneiro (Aug 25 2024 at 00:12):

Here's an alternative version:

partial def parse {v : Level} (M : Q(Type v)) (x : Q($M)) : MetaM (List Q($M)) := do
  match x with
  | ~q(@HAdd.hAdd $N₁ $N₂ _ (_) $x $y) =>
    let .defEq _  isDefEqQ (u := v) M N₁ | throwError "FIXME let's deal with this later"
    let .defEq _  isDefEqQ (u := v) M N₂ | throwError "FIXME let's deal with this later"
    let a  parse M x
    let b  parse M y
    pure (a ++ b)
  | e => pure [e]

𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Aug 25 2024 at 00:12):

In ~q(#HAdd.hAdd $N $N $N _ $x $y), you are specifying that the return type of the expression is N; but it is M by assumption, and Lean cannot unify them. Here is a simpler example of the same issue:

inductive Abc : Nat  Type where
  | mk : (n : Nat)  Abc n

example  : Abc 0  Nat
  /-
  type mismatch
    Abc.mk a
  has type
    Abc a : Type
  but is expected to have type
    Abc 0 : Type
  -/
  | .mk a => sorry

𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Aug 25 2024 at 00:14):

In Mario's version, ~q(@HAdd.hAdd $N₁ $N₂ _ (_) $x $y) leaves the output type unconstrained. And, afaict, it uses (_) because if you use _ in an instance position with Qq, Lean will try to infer it and fail.

Heather Macbeth (Aug 25 2024 at 00:18):

Thank you both, this helps a lot. Also this
Wojciech Nawrocki said:

In Mario's version, ~q(@HAdd.hAdd $N₁ $N₂ _ (_) $x $y) leaves the output type unconstrained. And, afaict, it uses (_) because if you use _ in an instance position with Qq, Lean will try to infer it and fail.

was new to me (and probably the missing piece of syntax that prevented me from bashing through by trial and error).

Heather Macbeth (Aug 25 2024 at 00:20):

By the way, I had hoped that after I pointed out to Qq that M and N₁ were the same, I would be able to use things of type Q(M) and Q(N₁) interchangeably. This is not the case (I'm getting errors from this). Is there a standard workaround here?

Heather Macbeth (Aug 25 2024 at 00:21):

For example, is there a syntax for matching like

  | ~q(@HAdd.hAdd M M _ (_) $x $y)

which really enforces that the things in the two M-spots are Ms?

Eric Wieser (Aug 25 2024 at 08:13):

If you want to only match homogeneous addition you can use HAdd.hAdd _ _ _ (@instHAdd $M (_)) $x $y

Eric Wieser (Aug 25 2024 at 08:14):

The syntax you ask for doesn't exist for Qq, just as it doesn't for syntax or regular matches


Last updated: May 02 2025 at 03:31 UTC