Zulip Chat Archive

Stream: lean4

Topic: Non-regular inductive type and universes


ohhaimark (Jul 09 2022 at 00:43):

Is it possible to give appropriate universe levels to the following inductive type

inductive term : Type  Type :=
  | var : {v : Type}  v  term v
  | app : term v  term v  term v
  | lam : term (Option v)  term v

or is it inheritly untypeable in lean?

Chris Bailey (Jul 09 2022 at 01:43):

No, you can't have (_ : Type) in the constructor args if your inductive is also in Type. You can make it a parameter, but then you won't be able to change it to Option _.

Kyle Miller (Jul 09 2022 at 04:12):

One way around this is to make your own type universe:

inductive MyType : Type :=
  | MyUnit
  | MyOption : MyType  MyType

def MyType.toType : MyType  Type
  | .MyUnit => Unit
  | .MyOption t => Option t.toType

instance : CoeSort MyType Type where
  coe := MyType.toType

inductive term : MyType  Type :=
  | var : {v : MyType}  v  term v
  | app : term v  term v  term v
  | lam : term (.MyOption v)  term v

James Gallicchio (Jul 09 2022 at 13:29):

Or you can just put it in Type 1

inductive term : Type  Type :=
  | var : {v : Type}  v  term v
  | app : term v  term v  term v
  | lam : term (Option v)  term v

a value a : A : Sort u cannot contain a B : Sort v unless u > v. In your def, each of the constructors takes a parameter v : Type 0, so the type must live in at least Type 1

James Gallicchio (Jul 09 2022 at 13:32):

But if you're building a Type 1 you should have pretty good justification for doing so -- types inhabiting higher universes are kinda annoying to work with sometimes

ohhaimark (Jul 10 2022 at 15:42):

Awesome. I am now stuck on a termination proof for bind

inductive Ty (v : Type) : Type :=
  | base : Ty v
  | option : Ty v  Ty v

def Ty.pure (v : Type) : Ty v := Ty.base (v:=v)

@[simp] def Ty.type : Ty v  Type
  | base => v
  | option ty => Option ty.type


instance : CoeSort (Ty v) Type where
  coe := Ty.type

inductive Term' : Ty v  Type
  | var : {a : Ty v}  a  Term' a
  | app : Term' a  Term' a  Term' a
  | lam : Term' (Ty.option a)  Term' a

def Term a := Term' $ Ty.pure a

namespace Term
@[matchPattern] def var := @Term'.var
@[matchPattern] def app := @Term'.app
@[matchPattern] def lam := @Term'.lam

def liftTermEq {ty : Ty v} {ty' : Ty w} (eq : ty.type = ty'.type) : Term' ty  Term' ty'
  | .var a => .var $ eq  a
  | .app t₁ t₂ => .app (liftTermEq eq t₁) (liftTermEq eq t₂)
  | .lam t => .lam (liftTermEq (by simp; rw [eq]) t)

def liftTerm' {ty : Ty v} : Term' ty  Term ty := liftTermEq (by rfl)

instance {ty : Ty v} : Coe (Term' ty) (Term ty) where
  coe := liftTerm'
instance {a : Type} : Coe (Term' (Ty.pure a).option) (Term (Option a)) where
  coe := liftTermEq (by rfl)
instance {a : Type} : Coe (Term (Option a)) (Term' (Ty.pure a).option) where
  coe := liftTermEq (by rfl)


def fvars : Term' ty  List ty
  | .var a => [a]
  | .app t₁ t₂ => fvars t₁ ++ fvars t₂
  | .lam t => (fvars t).bind (fun
    | none => []
    | some v => List.pure v)

@[simp] def depth : Term' ty  Nat
  | .var _ => 0
  | .app t₁ t₂ => max (depth t₁) (depth t₂) + 1
  | .lam t => depth t + 1

#check List

inductive TermHas {a} : {ty : Ty a}  ty  Term' ty  Prop :=
  | var : TermHas v (var v)
  | app₁ :  TermHas v t₁  TermHas v (app t₁ t₂)
  | app₂ :  TermHas v t₂  TermHas v (app t₁ t₂)
  | lam : {ty : Ty a}  {v : ty}  {t' : Term' ty.option}  TermHas (some v) t'  TermHas v (lam t')

@[simp] private def sizeBind (t : Term' ty) (f : (v : ty)  TermHas v t  Nat) : Nat := match t with
  | .var a => f a .var
  | .app t₁ t₂ => (sizeBind t₁ $ fun v h => f v $ .app₁ h) + (sizeBind t₂ $ fun v h => f v $ .app₂ h) + 1
  | .lam t' => sizeBind t' (fun v h => match v with
    | none => 0
    | some v => f v $ .lam h) + 1

@[simp] noncomputable def bindAuxSize (t : Term' ty) (f : (a : ty)  TermHas a t  Term' ty') : Nat := sizeBind t (fun v h => sizeOf $ f v h)

-- private def size_term_has_lt_bind
--   {ty : Ty v}
--   {ty' : Ty w}
--   (t' : Term' ty.option)
--   (b : ty)
--   (h : TermHas b (lam t'))
--   (f : (a : ty) → TermHas a (lam t') → Term' ty') :
--   sizeOf (f b h) < sizeBind t' (fun v h => match v with | none => 0 | some v => sizeOf $ f v $ .lam h) + 1
--   := by sorry

mutual
private def bindAux {ty : Ty v} {ty' : Ty w} (t : Term' ty) (f : (a : ty)  TermHas a t  Term' ty') : Term' ty' := match t with
  | .var a => f a .var
  | .app t₁ t₂ =>
      -- have : depth t₁ < max (depth t₁) (depth t₂) + 1 := by sorry
      -- have : depth t₂ < max (depth t₁) (depth t₂) + 1 := by sorry
      .app (bindAux t₁ $ fun v h => f v $ .app₁ h) (bindAux t₂ $ fun v h => f v $ .app₂ h)
  | .lam t' => .lam $ bindAux t' $ fun t h => match t with
      | none => var none
      | some v =>
          mapAux some (f v $ .lam h)
private def mapAux {ty : Ty v} {ty' : Ty w} (f : (ty  ty')) (t : Term' ty) : Term' ty' := bindAux t (fun v _ => .var $ f v)
end
termination_by
  bindAux t f => bindAuxSize t f + 1
  mapAux f t => sizeOf t
decreasing_by sorry

def pure (a : α) : Term α := Term.var a
def bind (t : Term α) (f : α  Term β) : Term β := bindAux t (fun v _ => f v)

instance : Monad Term where
  pure := pure
  bind := bind

end Term

I guess I can just apologize to lean for my lack of skills with `sorry'. Am I missing an easy WF relation to use, or tactics that can help me in the decreasing_by tactic?


Last updated: Dec 20 2023 at 11:08 UTC