Zulip Chat Archive

Stream: general

Topic: helped with quote theory


Frederick Pu (Nov 23 2025 at 05:58):

I'm working on a way to have quoted representations of Type that allow you to embed simpler type theories. I'm wondering if the lemma wompwomp is actually provable:

class UnquoteTy (Ty : Type) where
  -- `syntax T` returns Type describing the syntax of quoted type `T : Ty`
  «syntax» : Ty  Type
  -- `interpret t` returns Type describing the smenatics of quoted type `t : Ty`
  interpret : Ty  Type
  unquote  (T : Ty) (t : «syntax» T) : interpret T
  unquote_inj (T : Ty) : Function.Injective (unquote T)
  imp (α β : Ty) : Ty
  interpret_imp (α β : Ty) : interpret (imp α β) = (interpret α  interpret β)
  unit : Ty
  hUnit : interpret unit = Unit

infixr:30 "→" => UnquoteTy.imp
open UnquoteTy

theorem wompwomp {Ty : Type} [UnquoteTy Ty] {α β : Ty} :  «syntax» (αβ) = («syntax» α  «syntax» β) := by
  have qq := UnquoteTy.interpret_imp α β
  have := unquote (α  β)
  rw [qq] at this
  have := unquote β

Aaron Liu (Nov 23 2025 at 11:04):

My guess is no. What's your proof idea?

Robin Arnez (Nov 23 2025 at 13:56):

It's false:

class UnquoteTy (Ty : Type) where
  -- `syntax T` returns Type describing the syntax of quoted type `T : Ty`
  «syntax» : Ty  Type
  -- `interpret t` returns Type describing the smenatics of quoted type `t : Ty`
  interpret : Ty  Type
  unquote  (T : Ty) (t : «syntax» T) : interpret T
  unquote_inj (T : Ty) : Function.Injective (unquote T)
  imp (α β : Ty) : Ty
  interpret_imp (α β : Ty) : interpret (imp α β) = (interpret α  interpret β)
  unit : Ty
  hUnit : interpret unit = Unit

infixr:30 "→" => UnquoteTy.imp
open UnquoteTy

inductive Syntax where
  | imp (a b : Syntax)
  | unit

def Syntax.interpret : Syntax  Type
  | .unit => Unit
  | .imp a b => a.interpret  b.interpret

def Syntax.generate : (stx : Syntax)  stx.interpret
  | .unit => ()
  | .imp _a b => fun _ => b.generate

instance : UnquoteTy Syntax where
  «syntax» _ := Empty
  interpret := Syntax.interpret
  unquote := nofun
  unquote_inj := nofun
  imp := Syntax.imp
  unit := Syntax.unit
  interpret_imp _ _ := rfl
  hUnit := rfl

theorem not_wompwomp : ¬  {Ty : Type} [UnquoteTy Ty] {α β : Ty}, «syntax» (αβ) = («syntax» α  «syntax» β) := by
  simp only [Classical.not_forall]
  exists Syntax, inferInstance, .unit, .unit
  intro (h : Empty = (Empty  Empty))
  exact (h.mpr id).elim

Frederick Pu (Nov 23 2025 at 18:22):

what if we also make the syntax function injective?

class UnquoteTy (Ty : Type) where
  -- `syntax T` returns Type describing the syntax of quoted type `T : Ty`
  «syntax» : Ty  Type
  syntax_inj : Function.Injective «syntax»
  -- `interpret t` returns Type describing the smenatics of quoted type `t : Ty`
  interpret : Ty  Type
  unquote  (T : Ty) (t : «syntax» T) : interpret T
  unquote_inj (T : Ty) : Function.Injective (unquote T)
  imp (α β : Ty) : Ty
  interpret_imp (α β : Ty) : interpret (imp α β) = (interpret α  interpret β)
  unit : Ty
  hUnit : interpret unit = Unit

Edward van de Meent (Nov 23 2025 at 18:35):

that's gonna be hard to prove

Edward van de Meent (Nov 23 2025 at 18:36):

what's the (or an) intended implementation of the interpret function? I don't quite get what "a type describing the semantics of the quoted type" means...

Edward van de Meent (Nov 23 2025 at 18:36):

(nor why it should be injective)

Frederick Pu (Nov 23 2025 at 18:37):

it should be injective cause there's no point of having two elements of T that map to the same type

Frederick Pu (Nov 23 2025 at 18:37):

cause then you also get two syntaxs for the same type

Frederick Pu (Nov 23 2025 at 18:37):

i want you to be able reason about it as if it's type theory

Frederick Pu (Nov 23 2025 at 18:38):

also i think the equality is still unprovable because in theory the quoted functions could be a much smaller set

Frederick Pu (Nov 23 2025 at 18:38):

the more useful property i want is this anyways

Frederick Pu (Nov 23 2025 at 18:38):

-- can be defined using map and `UnquoteTy.interpret_imp`
def UnquoteTy.app {Ty : Type} [UnquoteTy Ty] {α β : Ty} : «syntax» (α  β)  «syntax» α  «syntax» β :=
  sorry

Frederick Pu (Nov 23 2025 at 18:41):

i mean seems like this would be non computable anyways tho lol

Aaron Liu (Nov 23 2025 at 18:46):

Frederick Pu said:

it should be injective cause there's no point of having two elements of T that map to the same type

Note that you can't prove Nat and Int are unequal in Lean

Aaron Liu (Nov 23 2025 at 18:47):

You also can't prove String and Int are unequal

Aaron Liu (Nov 23 2025 at 18:51):

This means you probably will never be able to instantiate a concrete instance of UnquoteTy

Aaron Liu (Nov 23 2025 at 18:51):

if you want syntax to be injective

Robin Arnez (Nov 23 2025 at 19:10):

It is constructible but I'm pretty sure you still can't prove your theorem about syntax:

class UnquoteTy (Ty : Type) where
  -- `syntax T` returns Type describing the syntax of quoted type `T : Ty`
  «syntax» : Ty  Type
  syntax_inj : Function.Injective «syntax»
  -- `interpret t` returns Type describing the semantics of quoted type `t : Ty`
  interpret : Ty  Type
  unquote  (T : Ty) (t : «syntax» T) : interpret T
  unquote_inj (T : Ty) : Function.Injective (unquote T)
  imp (α β : Ty) : Ty
  interpret_imp (α β : Ty) : interpret (imp α β) = (interpret α  interpret β)
  unit : Ty
  hUnit : interpret unit = Unit

infixr:30 "→" => UnquoteTy.imp
open UnquoteTy

inductive Syntax where
  | imp (a b : Syntax)
  | unit

def Syntax.interpret : Syntax  Type
  | .unit => Unit
  | .imp a b => a.interpret  b.interpret

def SyntaxTy := Quotient {
  r a b := Syntax.interpret a = Syntax.interpret b
  iseqv := {
    refl _ := rfl
    symm h := h.symm
    trans h h' := h.trans h'
  }
}

def Syntax.generate : (stx : Syntax)  stx.interpret
  | .unit => ()
  | .imp _a b => fun _ => b.generate

instance : UnquoteTy SyntaxTy where
  «syntax» := Quotient.lift Syntax.interpret (fun _ _ h => h)
  syntax_inj a b := by
    induction a, b using Quotient.inductionOn₂ with | _ a b
    exact Quot.sound (r := fun a b : Syntax => a.interpret = b.interpret)
  interpret := Quotient.lift Syntax.interpret (fun _ _ h => h)
  unquote _ := id
  unquote_inj _ := Function.injective_id
  imp := Quotient.lift₂ (fun a b => Quotient.mk _ (a.imp b))
    (fun a b c d h₁ h₂ => Quotient.sound (h₁  h₂  rfl : (a.interpret  b.interpret) = (c.interpret  d.interpret)))
  unit := Quotient.mk _ Syntax.unit
  interpret_imp := Quotient.ind₂ fun _ _ => rfl
  hUnit := rfl

Aaron Liu (Nov 23 2025 at 19:11):

of course why didn't I think of that

Robin Arnez (Nov 23 2025 at 19:17):

To demonstrate why it isn't provable, we can use the cardinality model:

import Mathlib

class UnquoteTy (Ty : Type) where
  -- `syntax T` returns Type describing the syntax of quoted type `T : Ty`
  «syntax» : Ty  Type
  syntax_inj : Function.Injective «syntax»
  -- `interpret t` returns Type describing the semantics of quoted type `t : Ty`
  interpret : Ty  Type
  unquote  (T : Ty) (t : «syntax» T) : interpret T
  unquote_inj (T : Ty) : Function.Injective (unquote T)
  imp (α β : Ty) : Ty
  interpret_imp (α β : Ty) : interpret (imp α β) = (interpret α  interpret β)
  unit : Ty
  hUnit : interpret unit = Unit

/-- Cardinality model -/
axiom eq_of_equiv (h : α  β) : α = β

infixr:30 "→" => UnquoteTy.imp
open UnquoteTy

instance : UnquoteTy Unit where
  «syntax» _ := Empty
  syntax_inj _ _ _ := rfl
  interpret _ := Unit
  unquote := nofun
  unquote_inj _ := nofun
  imp _ _ := ()
  unit := ()
  interpret_imp _ _ := eq_of_equiv fun _ _ => (), fun _ => (), fun _ => rfl, fun _ => rfl
  hUnit := rfl

theorem not_wompwomp : ¬  {Ty : Type} [UnquoteTy Ty] {α β : Ty}, «syntax» (αβ) = («syntax» α  «syntax» β) := by
  simp only [Classical.not_forall]
  exists Unit, inferInstance, .unit, .unit
  intro (h : Empty = (Empty  Empty))
  exact (h.mpr id).elim

Frederick Pu (Nov 23 2025 at 19:25):

if we do this is it possible to prove interpret_imp as a consequence?

class UnquoteTy (Ty : Type) where
  -- `syntax T` returns Type describing the syntax of quoted type `T : Ty`
  «syntax» : Ty  Type
  syntax_inj : Function.Injective «syntax»
  -- `interpret t` returns Type describing the smenatics of quoted type `t : Ty`
  interpret : Ty  Type
  unquote  (T : Ty) (t : «syntax» T) : interpret T
  unquote_inj (T : Ty) : Function.Injective (unquote T)
  imp (α β : Ty) : Ty
  -- interpret_imp (α β : Ty) : interpret (imp α β) = (interpret α → interpret β)
  app {α β : Ty} : «syntax» (imp α β)  «syntax» α  «syntax» β
  unit : Ty
  hUnit : interpret unit = Unit

Frederick Pu (Nov 23 2025 at 19:31):

seems like with all the extra injectivity lemmas it's better to just do this:

class UnquoteTy (Ty : Type) where
  -- `syntax T` returns Type describing the syntax of quoted type `T : Ty`
  «syntax» : Ty  Type
  -- `interpret t` returns Type describing the smenatics of quoted type `t : Ty`
  interpret : Ty  Type
  unquote  (T : Ty) (t : «syntax» T) : interpret T
  imp (α β : Ty) : Ty
  interpret_imp (α β : Ty) : interpret (imp α β) = (interpret α  interpret β)
  app {α β : Ty} : «syntax» (imp α β)  «syntax» α  «syntax» β
  unit : Ty
  hUnit : interpret unit = Unit

Frederick Pu (Nov 23 2025 at 19:44):

also do any of you know a way to have an instance of UnquoteTy for a simple type theory on nat?

Aaron Liu (Nov 23 2025 at 19:48):

what's the type theorey

Aaron Liu (Nov 23 2025 at 19:48):

can you describe it in words

Frederick Pu (Nov 23 2025 at 19:49):

im thinking the only types are Nat and Unit

Frederick Pu (Nov 23 2025 at 19:49):

and any function between them

Frederick Pu (Nov 23 2025 at 19:50):

recursive function are defined using something analagous to Nat.rec where the motive is fun (n : Nat) -> Nat

Frederick Pu (Nov 23 2025 at 19:50):

so like primitive recursion arithmetic

Frederick Pu (Nov 23 2025 at 19:52):

also im fine with unit not being implemented we can just have

class UnquoteTy (Ty : Type) where
  -- `syntax T` returns Type describing the syntax of quoted type `T : Ty`
  «syntax» : Ty  Type
  -- `interpret t` returns Type describing the smenatics of quoted type `t : Ty`
  interpret : Ty  Type
  unquote  (T : Ty) (t : «syntax» T) : interpret T
  imp (α β : Ty) : Ty
  interpret_imp (α β : Ty) : interpret (imp α β) = (interpret α  interpret β)
  app {α β : Ty} : «syntax» (imp α β)  «syntax» α  «syntax» β

Frederick Pu (Nov 24 2025 at 05:32):

does anyone know how i can do this recursion for the unquote?

def MyLang.syntax : MyLang  Type
| MyLang.A => Nat
| MyLang.Arrow MyLang.A MyLang.A => Unit
| MyLang.Arrow X Y => MyLang.syntax X  MyLang.syntax Y

def MyLang.interpret : MyLang  Type
| MyLang.A => Nat
| MyLang.Arrow X Y => MyLang.syntax X  MyLang.syntax Y

def MyLang.unquote : (T : MyLang)  T.syntax  T.interpret
| MyLang.A, t => t
| MyLang.Arrow MyLang.A MyLang.A, t => id
| MyLang.Arrow X Y, t => by {
  have : X  Y := by exact?
  unfold MyLang.syntax at t
}

i cant convice lean that these three are disjoint

Edward van de Meent (Nov 24 2025 at 08:40):

that's because they aren't? T could be MyLang.Arrow (MyLang.Arrow MyLang.A MyLang.A) (MyLang.Arrow MyLang.A MyLang.A)

Edward van de Meent (Nov 24 2025 at 08:42):

or, at least the X ≠ Y bit isn't true

Edward van de Meent (Nov 24 2025 at 08:50):

if you're explicit about the cases, this works:

def MyLang.unquote : (T : MyLang)  T.syntax  T.interpret
| MyLang.A, t => t
| MyLang.Arrow (MyLang.A) (MyLang.A), t => id
| MyLang.Arrow MyLang.A (MyLang.Arrow X Y), t => t
| MyLang.Arrow (MyLang.Arrow X Y) Z, t => t

Frederick Pu (Nov 24 2025 at 18:27):

ah thx

Frederick Pu (Nov 24 2025 at 18:29):

i think having syntax be an arbitrary type map allows too much leakage from lean's metatheory. I decided to do something more like a rule based sequent calculus on simple types where function are composed by composition (cut rule) in a continuation passing form:

class Unquote (Ty : Type) (rules : List (List Ty × Ty)) where
  -- `interpret t` returns Type describing the smenatics of quoted type `t : Ty`
  interpret : List Ty  Ty  Type
  unquote_intro (ruleIdx : Fin rules.length) : interpret (rules.get ruleIdx).1 (rules.get ruleIdx).2
  unquote_cut (Γ' Γ : List Ty) (T α : Ty) (a : interpret Γ' α) (t : interpret (α::Γ) T) : interpret (Γ' ++ Γ) T

inductive WompWomp (Ty : Type) (rules : List (List Ty × Ty)) : (Γ : List Ty)  (T : Ty)  Type where
| intro (ruleIdx : Fin rules.length) : WompWomp Ty rules (rules.get ruleIdx).1 (rules.get ruleIdx).2
| cut (Γ' Γ : List Ty) (T α : Ty) (a : WompWomp Ty rules Γ' α) (t : WompWomp Ty rules (α::Γ) T) : WompWomp Ty rules (Γ' ++ Γ) T

def WompWomp.unquote
  {Ty : Type} {rules : List (List Ty × Ty)}
  [U : Unquote Ty rules]
  : (Γ : List Ty)  (T : Ty)  WompWomp Ty rules Γ T 
      Unquote.interpret rules Γ T
| _, _, WompWomp.intro ruleIdx => U.unquote_intro ruleIdx
| _, _, WompWomp.cut Γ' Γ T α a t =>
  let ua := WompWomp.unquote Γ' α a
  let ut := WompWomp.unquote (α :: Γ) T t
  U.unquote_cut Γ' Γ T α ua ut

does anyone know if this forms a linear type system? Cause it seems like each value can only be used once and all values must be consumed


Last updated: Dec 20 2025 at 21:32 UTC