namespace Ex1

inductive T :=
  | int : Int -> T
  | tuple : List T -> T

@[reducible] def T.eval (t : T) : Type :=
  @T.rec
    (motive_1 := fun _ => Type)
    (motive_2 := fun _ => Type)
    (fun _ => Int)
    (fun _ ih => ih)
    Unit
    (fun _ _ ih₁ ih₂ => ih₁ × ih₂)
    t

@[reducible] def T.evalList (t : List T) : Type :=
  @T.rec_1
    (motive_1 := fun _ => Type)
    (motive_2 := fun _ => Type)
    (fun _ => Int)
    (fun _ ih => ih)
    Unit
    (fun _ _ ih₁ ih₂ => ih₁ × ih₂)
    t

mutual
  def T.default (τ : T): τ.eval :=
    match τ with
    | T.int v => v
    | T.tuple τs => defaultList τs

  def T.defaultList (τs : List T) : T.evalList τs :=
    match τs with
    | []    => ()
    | τ::τs => (τ.default, defaultList τs)
end

#guard T.default (.int 5) == 5
#guard T.default (.tuple [.int 5]) == (5, ())
#guard T.default (.tuple [.int 5, .int 6]) == (5, 6, ())

end Ex1

namespace Ex2

inductive T :=
  | int : Int -> T
  | tuple : List T -> T

@[reducible] def T.eval (t : T) : Type :=
  @T.rec
    (motive_1 := fun _ => Type)
    (motive_2 := fun _ => Type)
    (fun _ => Int)
    (fun _ ih => ih)
    Unit
    (fun _ τs ih₁ ih₂ =>
      match τs with
      | [] => ih₁
      | _  => ih₁ × ih₂)
    t

@[reducible] def T.evalList (t : List T) : Type :=
  @T.rec_1
    (motive_1 := fun _ => Type)
    (motive_2 := fun _ => Type)
    (fun _ => Int)
    (fun _ ih => ih)
    Unit
    (fun _ τs ih₁ ih₂ =>
      match τs with
      | [] => ih₁
      | _  => ih₁ × ih₂)
    t

mutual
  def T.default (τ : T): τ.eval :=
    match τ with
    | T.int v => v
    | T.tuple τs => defaultList τs

  def T.defaultList (τs : List T) : T.evalList τs :=
    match τs with
    | []    => ()
    | [τ]   => τ.default
    | τ₁::τ₂::τs => (τ₁.default, defaultList (τ₂::τs))
end

#guard T.default (.int 5) == 5
#guard T.default (.tuple [.int 5]) == 5
#guard T.default (.tuple [.int 5, .int 6]) == (5, 6)

end Ex2
