Zulip Chat Archive

Stream: new members

Topic: Strange metavariable error when using rewrite rules


Becky T (May 03 2025 at 15:21):

Greetings:

With the following code:

import Mathlib.Init

universe u

axiom Bird : Type u
axiom response : Bird  Bird  Bird
infixl:100 " ◁ " => response
axiom compose : Bird  Bird  Bird
infixr:80 " ∘ " => compose
axiom composition (A B : Bird) :  {x : Bird}, (A  B)  x = A  (B  x)


namespace Combinator





  axiom K : Bird
  axiom K.call :  (x y : Bird), (K  x)  y = x

  axiom I : Bird
  axiom I.call :  (x : Bird), (I  x) = x

  axiom B : Bird
  axiom B.call :  (x y z : Bird), (((B  x)  y)  z) = x  (y  z)

  axiom S : Bird
  axiom S.call :  (x y z : Bird), (((S  x)  y)  z) = (x  z)  (y  z)

  axiom C : Bird
  axiom C.call :  (x y z : Bird), (((C  x)  y)  z) =  (x  z)  y

  axiom W : Bird
  axiom W.call :  (x y : Bird), (W  x)  y = (x  y)  y

end Combinator

open Combinator

axiom S' : Bird
axiom S'.call :   (x y z : Bird), (((S'  x)  y)  z) = (x  (y  z))  z


axiom c1 : Bird
axiom c1.call :   (x y z : Bird), (((c1  x)  y)  z) = ((((B  (B  W))  B)  x)  y)  z

theorem c1_correct :  x y z : Bird, S'  x  y  z = c1  x  y  z := by
intros x y z;
rw [S'.call];
rw [c1.call];
rw [B.call];
rw [B.call];
rw [W.call];
rw [B.call];

I end up with the following error message:

declaration 'c1_correct' contains universe level metavariables at the expression
  response.{?u.3995, u_3, u_4} (response.{u_1, ?u.3991, ?u.3995} x (response.{u_2, u_3, ?u.3991} y z)) z
in the declaration body

fun x y z 
    Eq.mpr
      (id
        (congrArg (fun _a  _a = c1  x  y  z) (S'.call.{u_1, u_2, u_3, u_4, u_5, u_6, u_7, ?u.3995, ?u.3991} x y z)))
      (Eq.mpr
        (id
          (congrArg
            (fun _a 
              response.{?u.3995, u_3, u_4} (response.{u_1, ?u.3991, ?u.3995} x (response.{u_2, u_3, ?u.3991} y z)) z =
                _a)
            (c1.call.{u_1, ?u.3893, ?u.3892, ?u.3992, ?u.3891, ?u.3931, ?u.3930, ?u.3963, u_2, u_3, u_4, u_8, u_9, u_10,
                ?u.3964, ?u.3932}
              x y z)))
        (Eq.mpr
          (id
            (congrArg
              (fun (_a : Bird.{?u.3932}) 
                response.{?u.3995, u_3, u_4} (response.{u_1, ?u.3991, ?u.3995} x (response.{u_2, u_3, ?u.3991} y z)) z =
                  response.{?u.3964, u_3, u_4} (response.{?u.3932, u_2, ?u.3964} _a y) z)
              (B.call.{?u.3931, ?u.3992, u_1, ?u.3932, ?u.3893, ?u.3892, ?u.3891, ?u.3993}
                (response.{?u.3930, ?u.3963, ?u.3931} B.{?u.3930} W.{?u.3963}) B.{?u.3992} x)))
          (Eq.mpr
            (id
              (congrArg
                (fun (_a : Bird.{?u.3964}) 
                  response.{?u.3995, u_3, u_4} (response.{u_1, ?u.3991, ?u.3995} x (response.{u_2, u_3, ?u.3991} y z))
                      z =
                    response.{?u.3964, u_3, u_4} _a z)
                (B.call.{?u.3963, ?u.3993, u_2, ?u.3964, ?u.3932, ?u.3931, ?u.3930, ?u.3994} W.{?u.3963}
                  (response.{?u.3992, u_1, ?u.3993} B.{?u.3992} x) y)))
            (Eq.mpr
              (id
                (congrArg
                  (fun _a 
                    response.{?u.3995, u_3, u_4} (response.{u_1, ?u.3991, ?u.3995} x (response.{u_2, u_3, ?u.3991} y z))
                        z =
                      _a)
                  (W.call.{?u.3994, u_3, u_4, ?u.3964, ?u.3963, ?u.3995}
                    (response.{?u.3993, u_2, ?u.3994} (response.{?u.3992, u_1, ?u.3993} B.{?u.3992} x) y) z)))
              (Eq.mpr
                (id
                  (congrArg
                    (fun (_a : Bird.{?u.3995}) 
                      response.{?u.3995, u_3, u_4}
                          (response.{u_1, ?u.3991, ?u.3995} x (response.{u_2, u_3, ?u.3991} y z)) z =
                        response.{?u.3995, u_3, u_4} _a z)
                    (B.call.{u_1, u_2, u_3, ?u.3995, ?u.3994, ?u.3993, ?u.3992, ?u.3991} x y z)))
                (Eq.refl
                  (response.{?u.3995, u_3, u_4} (response.{u_1, ?u.3991, ?u.3995} x (response.{u_2, u_3, ?u.3991} y z))
                    z)))))))

I am not sure how to start debugging the proof term, so any advice would be very much appreciated!

Kyle Miller (May 03 2025 at 15:36):

when you define

axiom Bird : Type u

this defines a whose family of Bird constants, one for every universe level u (full notation: Bird.{u}). The u is not a fixed constant. Whenever you mention Bird without the full notation, Lean interprets it as Bird.{_}, using a fresh universe level metavariable at _. Lean requires that universe level metavariables all be solved for.

The easiest fix is to go back to the axiom and instead define

axiom Bird : Type

This creates one type Bird in only the Type universe. There are no universe level metavariables that need to be solved for.

Becky T (May 03 2025 at 16:20):

Thank you! I presume that means that the universe declaration is not needed? I presume Lean has some sort of built-in universe polymorphism that deals with this.

Kyle Miller (May 03 2025 at 16:46):

The function of universe u is to make it legal to refer to u and have it automatically become a universe parameter for the declaration.

Doing

universe u
axiom Bird : Type u
```
is the same as
```
axiom Bird.{u} : Type u
```
The key thing to realize, what I was saying about how `Bird` by itself in your code means `Bird.{_}`, is that `u` is not fixed for the whole module. Each individual use of `Bird` can have its own `u` so to speak. You would need to consistently write `Bird.{u}` yourself for every `Bird` to be in the same universe.

Kyle Miller (May 03 2025 at 16:46):

Becky T said:

Lean has some sort of built-in universe polymorphism that deals with this.

My suggestion to remove u in Type u is to make it non-polymorphic.

Edward van de Meent (May 03 2025 at 17:51):

if you want to say "let Bird be some element of Type u", use variables instead

Edward van de Meent (May 03 2025 at 17:52):

that will "fix" the universe level (sort of)

Kyle Miller (May 04 2025 at 01:19):

Won't that cause every combinator to be a function of Bird, which would mean needing to pass Bird in as an argument?

Edward van de Meent (May 04 2025 at 12:05):

:hmm: i guess you could bundle it all in an instance?

Edward van de Meent (May 04 2025 at 12:08):

something like

import Mathlib.Init
set_option autoImplicit false

universe u
class Forest (Bird : Type u) where
  response : Bird  Bird  Bird
  compose : Bird  Bird  Bird
  composition (a b : Bird) :  x : Bird, response (compose a b) x = response a (response b x)

infixl:100 " ◁ " => Forest.response

infixr:80 " ∘ " => Forest.compose

variable {Bird : Type u} [Forest Bird]
-- whatever stuff you want to do

Last updated: Dec 20 2025 at 21:32 UTC