An important part of the interface of a function is the parameter names, for making used of named arguments. This PR makes the parameter names print in a reliable way. The parameters of the type now appear as hygienic names if they cannot be used as named arguments. Modifies the heuristic for how parameters are chosen to appear before or after the colon. The rule is now that parameters start appearing after the colon at the first non-dependent non-instance-implicit parameter that has a name unusable as a named argument. This is a refinement of #2846. Fixes the issue where consecutive hygienic names pretty print without a space separating them, so we now have `(x✝ y✝ : Nat)` rather than `(x✝y✝ : Nat)`. Breaking change: `Lean.PrettyPrinter.Formatter.pushToken` now takes an additional boolean `ident` argument, which should be `true` for identifiers. Used to insert discretionary space between consecutive identifiers. Closes #5810
706 lines
18 KiB
Text
706 lines
18 KiB
Text
set_option guard_msgs.diff true
|
||
|
||
/-!
|
||
Mutual structural recursion.
|
||
|
||
In this file, we often attach a `termination_by structural` annotation to at least
|
||
one of the functions to force structural recursion. We don't want lean to resort to
|
||
well-founded recursion if structural recursion fails somehow.
|
||
-/
|
||
|
||
mutual
|
||
inductive A
|
||
| self : A → A
|
||
| other : B → A
|
||
| empty
|
||
inductive B
|
||
| self : B → B
|
||
| other : A → B
|
||
| empty
|
||
end
|
||
|
||
-- A simple mutually recursive function definition
|
||
|
||
mutual
|
||
def A.size : A → Nat
|
||
| .self a => a.size + 1
|
||
| .other b => b.size + 1
|
||
| .empty => 0
|
||
termination_by structural x => x
|
||
|
||
def B.size : B → Nat
|
||
| .self b => b.size + 1
|
||
| .other a => a.size + 1
|
||
| .empty => 0
|
||
end
|
||
|
||
|
||
-- And indeed all equationals hold definitionally
|
||
|
||
theorem A_size_eq1 (a : A) : (A.self a).size = a.size + 1 := rfl
|
||
theorem A_size_eq2 (b : B) : (A.other b).size = b.size + 1 := rfl
|
||
theorem A_size_eq3 : A.empty.size = 0 := rfl
|
||
theorem B_size_eq1 (b : B) : (B.self b).size = b.size + 1 := rfl
|
||
theorem B_size_eq2 (a : A) : (B.other a).size = a.size + 1 := rfl
|
||
theorem B_size_eq3 : B.empty.size = 0 := rfl
|
||
|
||
-- The expected equational theorems are produced
|
||
|
||
/-- info: A.size.eq_1 (a : A) : a.self.size = a.size + 1 -/
|
||
#guard_msgs in
|
||
#check A.size.eq_1
|
||
|
||
/-- info: A.size.eq_2 (b : B) : (A.other b).size = b.size + 1 -/
|
||
#guard_msgs in
|
||
#check A.size.eq_2
|
||
|
||
/-- info: A.size.eq_3 : A.empty.size = 0 -/
|
||
#guard_msgs in
|
||
#check A.size.eq_3
|
||
|
||
/-- info: B.size.eq_1 (b : B) : b.self.size = b.size + 1 -/
|
||
#guard_msgs in
|
||
#check B.size.eq_1
|
||
|
||
/-- info: B.size.eq_2 (a : A) : (B.other a).size = a.size + 1 -/
|
||
#guard_msgs in
|
||
#check B.size.eq_2
|
||
|
||
/-- info: B.size.eq_3 : B.empty.size = 0 -/
|
||
#guard_msgs in
|
||
#check B.size.eq_3
|
||
|
||
-- Smart unfolding works
|
||
|
||
/--
|
||
info: a : A
|
||
h : (B.other a).size = 1
|
||
⊢ a.size = 0
|
||
-/
|
||
#guard_msgs in
|
||
theorem ex1 (a : A) (h : (A.other (B.other a)).size = 2) : a.size = 0 := by
|
||
injection h with h
|
||
trace_state -- without smart unfolding the state would be a mess
|
||
injection h with h
|
||
|
||
-- And it computes in type just fine
|
||
|
||
mutual
|
||
def A.subs : (a : A) → (Fin a.size → A ⊕ B)
|
||
| .self a => Fin.lastCases (.inl a) (a.subs)
|
||
| .other b => Fin.lastCases (.inr b) (b.subs)
|
||
| .empty => Fin.elim0
|
||
termination_by structural x => x
|
||
def B.subs : (b : B) → (Fin b.size → A ⊕ B)
|
||
| .self b => Fin.lastCases (.inr b) (b.subs)
|
||
| .other a => Fin.lastCases (.inl a) (a.subs)
|
||
| .empty => Fin.elim0
|
||
end
|
||
|
||
|
||
-- We can define mutually recursive theorems as well
|
||
|
||
mutual
|
||
def A.hasNoBEmpty : A → Prop
|
||
| .self a => a.hasNoBEmpty
|
||
| .other b => b.hasNoBEmpty
|
||
| .empty => True
|
||
termination_by structural x => x
|
||
def B.hasNoBEmpty : B → Prop
|
||
| .self b => b.hasNoBEmpty
|
||
| .other a => a.hasNoBEmpty
|
||
| .empty => False
|
||
end
|
||
|
||
-- Mixing Prop and Nat.
|
||
-- This works because both `Prop` and `Nat` are in the same universe (`Type`)
|
||
|
||
mutual
|
||
open Classical
|
||
noncomputable
|
||
def A.hasNoAEmpty : A → Prop
|
||
| .self a => a.hasNoAEmpty
|
||
| .other b => b.oddCount > 0
|
||
| .empty => False
|
||
termination_by structural x => x
|
||
noncomputable
|
||
def B.oddCount : B → Nat
|
||
| .self b => b.oddCount + 1
|
||
| .other a => if a.hasNoAEmpty then 0 else 1
|
||
| .empty => 0
|
||
end
|
||
|
||
-- Higher levels, but the same level `Type u`
|
||
|
||
mutual
|
||
open Classical
|
||
def A.type.{u} : A → Type u
|
||
| .self a => Unit × a.type
|
||
| .other b => Unit × b.type
|
||
| .empty => PUnit
|
||
termination_by structural x => x
|
||
def B.type.{u} : B → Type u
|
||
| .self b => PUnit × b.type
|
||
| .other a => PUnit × a.type
|
||
| .empty => PUnit
|
||
end
|
||
|
||
|
||
-- Mixed levels, should error
|
||
|
||
/--
|
||
error: invalid mutual definition, result types must be in the same universe level, resulting type for `A.strangeType` is
|
||
Type : Type 1
|
||
and for `B.odderCount` is
|
||
Nat : Type
|
||
-/
|
||
#guard_msgs in
|
||
mutual
|
||
open Classical
|
||
def A.strangeType : A → Type
|
||
| .self a => Unit × a.strangeType
|
||
| .other b => Fin b.odderCount
|
||
| .empty => Unit
|
||
termination_by structural x => x
|
||
def B.odderCount : B → Nat
|
||
| .self b => b.odderCount + 1
|
||
| .other a => if Nonempty a.strangeType then 0 else 1
|
||
| .empty => 0
|
||
end
|
||
|
||
|
||
namespace Index
|
||
|
||
/-! An example where the data type has parameters and indices -/
|
||
|
||
mutual
|
||
inductive A (m : Nat) : Nat → Type
|
||
| self : A m n → A m (n+m)
|
||
| other : B m n → A m (n+m)
|
||
| empty : A m 0
|
||
inductive B (m : Nat) : Nat → Type
|
||
| self : B m n → B m (n+m)
|
||
| other : A m n → B m (n+m)
|
||
| empty : B m 0
|
||
end
|
||
|
||
mutual
|
||
def A.size {m n : Nat} : A m n → Nat
|
||
| .self a => a.size + m
|
||
| .other b => b.size + m
|
||
| .empty => 0
|
||
termination_by structural x => x
|
||
def B.size {m n : Nat} : B m n → Nat
|
||
| .self b => b.size + m
|
||
| .other a => a.size + m
|
||
| .empty => 0
|
||
end
|
||
|
||
mutual
|
||
theorem A.size_eq_index (m n : Nat) : (a : A m n) → a.size = n
|
||
| .self a => by dsimp [A.size]; rw[ A.size_eq_index]
|
||
| .other b => by dsimp [A.size]; rw [B.size_eq_index]
|
||
| .empty => rfl
|
||
termination_by structural x => x
|
||
theorem B.size_eq_index (m n : Nat) : (b : B m n) → b.size = n
|
||
| .self b => by dsimp [B.size]; rw [B.size_eq_index]
|
||
| .other a => by dsimp [B.size]; rw [A.size_eq_index]
|
||
| .empty => rfl
|
||
end
|
||
|
||
end Index
|
||
|
||
|
||
namespace EvenOdd
|
||
|
||
-- Mutual structural recursion over a non-mutual inductive type
|
||
|
||
-- (The functions don't actually implement even/odd, but that isn't the point here.)
|
||
|
||
mutual
|
||
def Even : Nat → Prop
|
||
| 0 => True
|
||
| n+1 => ¬ Odd n
|
||
termination_by structural x => x
|
||
|
||
def Odd : Nat → Prop
|
||
| 0 => False
|
||
| n+1 => ¬ Even n
|
||
end
|
||
|
||
mutual
|
||
def isEven : Nat → Bool
|
||
| 0 => true
|
||
| n+1 => ! isOdd n
|
||
termination_by structural x => x
|
||
|
||
def isOdd : Nat → Bool
|
||
| 0 => false
|
||
| n+1 => ! isEven n
|
||
end
|
||
|
||
theorem isEven_eq_2 (n : Nat) : isEven (n+1) = ! isOdd n := rfl
|
||
|
||
/-- info: EvenOdd.isEven.eq_1 : isEven 0 = true -/
|
||
#guard_msgs in
|
||
#check isEven.eq_1
|
||
|
||
theorem eq_true_of_not_eq_false {b : Bool} : (! b) = false → b = true := by simp
|
||
theorem eq_false_of_not_eq_true {b : Bool} : (! b) = true → b = false := by simp
|
||
|
||
/--
|
||
info: n : Nat
|
||
h : EvenOdd.isOdd (n + 1) = false
|
||
⊢ EvenOdd.isEven n = true
|
||
-/
|
||
#guard_msgs in
|
||
theorem ex1 (n : Nat) (h : isEven (n+2) = true) : isEven n = true := by
|
||
replace h := eq_false_of_not_eq_true h
|
||
trace_state -- without smart unfolding the state would be a mess
|
||
replace h := eq_true_of_not_eq_false h
|
||
exact h
|
||
|
||
end EvenOdd
|
||
|
||
namespace MutualIndNonMutualFun
|
||
|
||
mutual
|
||
inductive A
|
||
| self : A → A
|
||
| other : B → A
|
||
| empty
|
||
inductive B
|
||
| self : B → B
|
||
| other : A → B
|
||
| empty
|
||
end
|
||
|
||
-- Structural recursion ignoring some types of the mutual inductive
|
||
|
||
def A.self_size : A → Nat
|
||
| .self a => a.self_size + 1
|
||
| .other _ => 0
|
||
| .empty => 0
|
||
termination_by structural x => x
|
||
|
||
def B.self_size : B → Nat
|
||
| .self b => b.self_size + 1
|
||
| .other _ => 0
|
||
| .empty => 0
|
||
termination_by structural x => x
|
||
|
||
def A.self_size_with_param : Nat → A → Nat
|
||
| n, .self a => a.self_size_with_param n + n
|
||
| _, .other _ => 0
|
||
| _, .empty => 0
|
||
termination_by structural _ x => x
|
||
|
||
-- Structural recursion with more than one function per types of the mutual inductive
|
||
|
||
mutual
|
||
def A.weird_size1 : A → Nat
|
||
| .self a => a.weird_size2 + 1
|
||
| .other _ => 0
|
||
| .empty => 0
|
||
termination_by structural x => x
|
||
def A.weird_size2 : A → Nat
|
||
| .self a => a.weird_size3 + 1
|
||
| .other _ => 0
|
||
| .empty => 0
|
||
def A.weird_size3 : A → Nat
|
||
| .self a => a.weird_size1 + 1
|
||
| .other _ => 0
|
||
| .empty => 0
|
||
end
|
||
|
||
-- We have equality
|
||
theorem A.weird_size1_eq_1 (a : A) : (A.self a).weird_size1 = a.weird_size2 + 1 := rfl
|
||
|
||
-- And the right equational theorems
|
||
/--
|
||
info: MutualIndNonMutualFun.A.weird_size1.eq_1 (a : A) : a.self.weird_size1 = a.weird_size2 + 1
|
||
-/
|
||
#guard_msgs in
|
||
#check A.weird_size1.eq_1
|
||
|
||
end MutualIndNonMutualFun
|
||
|
||
namespace DifferentTypes
|
||
|
||
-- Check error message when argument types are not mutually recursive
|
||
|
||
inductive A
|
||
| self : A → A
|
||
| empty
|
||
|
||
/--
|
||
error: failed to infer structural recursion:
|
||
Skipping arguments of type A, as DifferentTypes.Nat.foo has no compatible argument.
|
||
Skipping arguments of type Nat, as DifferentTypes.A.with_nat has no compatible argument.
|
||
-/
|
||
#guard_msgs in
|
||
mutual
|
||
def A.with_nat : A → Nat
|
||
| .self a => a.with_nat + Nat.foo 1
|
||
| .empty => 0
|
||
termination_by structural x => x
|
||
def Nat.foo : Nat → Nat
|
||
| n+1 => Nat.foo n
|
||
| 0 => A.empty.with_nat
|
||
end
|
||
|
||
end DifferentTypes
|
||
|
||
namespace FixedIndex
|
||
|
||
/- Do we run into problems if one of the indices is part of the “fixed prefix”? -/
|
||
|
||
inductive T : Nat → Type
|
||
| a : T 37
|
||
| b : T n → T n
|
||
|
||
def T.size (n : Nat) (start : Nat) : T n → Nat
|
||
| a => start
|
||
| b t => 1 + T.size n start t
|
||
termination_by structural t => t
|
||
|
||
namespace Mutual
|
||
mutual
|
||
def T.size1 (n : Nat) (start : Nat) : T n → Nat
|
||
| .a => 0
|
||
| .b t => 1 + T.size2 n start t
|
||
termination_by structural t => t
|
||
|
||
def T.size2 (n : Nat) (start : Nat) : T n → Nat
|
||
| .a => 0
|
||
| .b t => 1 + T.size1 n start t
|
||
end
|
||
|
||
end Mutual
|
||
|
||
namespace Mutual2
|
||
|
||
mutual
|
||
inductive A : Nat → Type
|
||
| a : A n
|
||
| b : B → A n → A n
|
||
inductive B : Type
|
||
| a : ((n : Nat) → A n) → B
|
||
end
|
||
|
||
-- In this test A and B have `n start` as fixed prefix, but only
|
||
-- in `A` the `n` is an index
|
||
|
||
set_option linter.constructorNameAsVariable false in
|
||
mutual
|
||
def A.size (n : Nat) (start : Nat) : A n → Nat
|
||
| .a => 0
|
||
| .b b a => 1 + B.size n start b + A.size n start a
|
||
termination_by structural t => t
|
||
|
||
def B.size (n : Nat) (start : Nat) : B → Nat
|
||
| .a a => 1 + A.size n start (a n)
|
||
end
|
||
|
||
end Mutual2
|
||
|
||
namespace Mutual3
|
||
|
||
mutual
|
||
inductive A (n : Nat) : Type
|
||
| a : A n
|
||
| b : B n → A n
|
||
inductive B (n : Nat) : Type
|
||
| a : A n → B n
|
||
end
|
||
|
||
/--
|
||
error: cannot use specified parameter for structural recursion:
|
||
its type is an inductive datatype
|
||
A n
|
||
and the datatype parameter
|
||
n
|
||
depends on the function parameter
|
||
n
|
||
which does not come before the varying parameters and before the indices of the recursion parameter.
|
||
-/
|
||
#guard_msgs in
|
||
set_option linter.constructorNameAsVariable false in
|
||
mutual
|
||
def A.size (n : Nat) (m : Nat) : A n → Nat
|
||
| .a => 0
|
||
| .b b => 1 + B.size m n b
|
||
termination_by structural t => t
|
||
|
||
def B.size (n : Nat) (m : Nat) : B m → Nat
|
||
| .a a => 1 + A.size m n a
|
||
end
|
||
|
||
end Mutual3
|
||
|
||
/--
|
||
error: cannot use specified parameter for structural recursion:
|
||
its type FixedIndex.T is an inductive family and indices are not variables
|
||
T 37
|
||
-/
|
||
#guard_msgs in
|
||
def T.size2 : T 37 → Nat
|
||
| a => 0
|
||
| b t => 1 + T.size2 t
|
||
termination_by structural t => t
|
||
|
||
end FixedIndex
|
||
|
||
namespace IndexIsParameter
|
||
|
||
-- Not actual mutual, but since I was at it
|
||
|
||
inductive T (n : Nat) : Nat → Type where
|
||
| z : T n n
|
||
| n : T n n → T n n
|
||
|
||
/--
|
||
error: cannot use specified parameter for structural recursion:
|
||
its type is an inductive datatype
|
||
T n n
|
||
and the datatype parameter
|
||
n
|
||
depends on the function parameter
|
||
n
|
||
which does not come before the varying parameters and before the indices of the recursion parameter.
|
||
-/
|
||
#guard_msgs in
|
||
def T.a {n : Nat} : T n n → Nat
|
||
| .z => 0
|
||
| .n t => t.a + 1
|
||
termination_by structural t => t
|
||
|
||
|
||
end IndexIsParameter
|
||
|
||
|
||
namespace DifferentParameters
|
||
|
||
-- An attempt to make it fall over mutual recursion over the same type
|
||
-- but with different parameters.
|
||
|
||
inductive T (n : Nat) : Type where
|
||
| z : T n
|
||
| n : T n → T n
|
||
|
||
/--
|
||
error: failed to infer structural recursion:
|
||
Skipping arguments of type T 23, as DifferentParameters.T.b has no compatible argument.
|
||
Skipping arguments of type T 42, as DifferentParameters.T.a has no compatible argument.
|
||
-/
|
||
#guard_msgs in
|
||
mutual
|
||
def T.a : T 23 → Nat
|
||
| .z => 0
|
||
| .n t => t.a + 1 + T.b .z
|
||
termination_by structural t => t
|
||
def T.b : T 42 → Nat
|
||
| .z => 0
|
||
| .n t => t.b + 1 + T.a .z
|
||
end
|
||
|
||
end DifferentParameters
|
||
|
||
namespace ManyCombinations
|
||
-- A datatype with no size function, to avoid well-founded recursion
|
||
|
||
inductive Nattish
|
||
| zero
|
||
| cons : (Nat → Nattish) → Nattish
|
||
|
||
/--
|
||
error: fail to show termination for
|
||
ManyCombinations.f
|
||
ManyCombinations.g
|
||
with errors
|
||
failed to infer structural recursion:
|
||
Too many possible combinations of parameters of type Nattish (or please indicate the recursive argument explicitly using `termination_by structural`).
|
||
|
||
|
||
Could not find a decreasing measure.
|
||
The arguments relate at each recursive call as follows:
|
||
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
|
||
Call from ManyCombinations.f to ManyCombinations.g at 557:15-29:
|
||
#1 #2 #3 #4
|
||
#5 ? ? ? ?
|
||
#6 ? = ? ?
|
||
#7 ? ? = ?
|
||
#8 ? ? ? =
|
||
Call from ManyCombinations.g to ManyCombinations.f at 560:15-29:
|
||
#5 #6 #7 #8
|
||
#1 _ _ _ _
|
||
#2 _ = _ _
|
||
#3 _ _ = _
|
||
#4 _ _ _ =
|
||
|
||
|
||
#1: sizeOf a
|
||
#2: sizeOf b
|
||
#3: sizeOf c
|
||
#4: sizeOf d
|
||
#5: sizeOf a
|
||
#6: sizeOf b
|
||
#7: sizeOf c
|
||
#8: sizeOf d
|
||
|
||
Please use `termination_by` to specify a decreasing measure.
|
||
-/
|
||
#guard_msgs in
|
||
mutual
|
||
def f (a b c d : Nattish) : Nat := match a with
|
||
| .zero => 0
|
||
| .cons n => g (n 23) b c d
|
||
def g (a b c d : Nattish) : Nat := match a with
|
||
| .zero => 0
|
||
| .cons n => f (n 42) b c d
|
||
end
|
||
|
||
-- specifying one `termination_by structural` helps
|
||
|
||
#guard_msgs in
|
||
mutual
|
||
def f' (a b c d : Nattish) : Nat := match a with
|
||
| .zero => 0
|
||
| .cons n => g' (n 23) b c d
|
||
termination_by structural a
|
||
def g' (a b c d : Nattish) : Nat := match a with
|
||
| .zero => 0
|
||
| .cons n => f' (n 42) b c d
|
||
end
|
||
|
||
end ManyCombinations
|
||
|
||
namespace WithTuple
|
||
|
||
inductive Tree (α : Type) where
|
||
| node : α → (Tree α × Tree α) → Tree α
|
||
|
||
mutual
|
||
|
||
def Tree.map (f : α → β) (x : Tree α): Tree β :=
|
||
match x with
|
||
| node x arrs => node (f x) $ Tree.map_tup f arrs
|
||
termination_by structural x
|
||
|
||
def Tree.map_tup (f : α → β) (x : Tree α × Tree α): (Tree β × Tree β) :=
|
||
match x with
|
||
| (t₁,t₂) => (Tree.map f t₁, Tree.map f t₂)
|
||
termination_by structural x
|
||
|
||
end
|
||
|
||
end WithTuple
|
||
|
||
namespace WithArray
|
||
|
||
inductive Tree (α : Type) where
|
||
| node : α → Array (Tree α) → Tree α
|
||
|
||
mutual
|
||
|
||
def Tree.map (f : α → β) (x : Tree α): Tree β :=
|
||
match x with
|
||
| node x arr₁ => node (f x) $ Tree.map_arr f arr₁
|
||
termination_by structural x
|
||
|
||
def Tree.map_arr (f : α → β) (x : Array (Tree α)): Array (Tree β) :=
|
||
match x with
|
||
| .mk arr₁ => .mk (Tree.map_list f arr₁)
|
||
termination_by structural x
|
||
|
||
def Tree.map_list (f : α → β) (x : List (Tree α)): List (Tree β) :=
|
||
match x with
|
||
| [] => []
|
||
| h₁::t₁ => (Tree.map f h₁)::Tree.map_list f t₁
|
||
termination_by structural x
|
||
end
|
||
|
||
end WithArray
|
||
|
||
namespace FunIndTests
|
||
|
||
-- FunInd does not handle mutual structural recursion yet, so make sure we error
|
||
-- out nicely
|
||
|
||
/--
|
||
info: A.size.induct (motive_1 : A → Prop) (motive_2 : B → Prop) (case1 : ∀ (a : A), motive_1 a → motive_1 a.self)
|
||
(case2 : ∀ (b : B), motive_2 b → motive_1 (A.other b)) (case3 : motive_1 A.empty)
|
||
(case4 : ∀ (b : B), motive_2 b → motive_2 b.self) (case5 : ∀ (a : A), motive_1 a → motive_2 (B.other a))
|
||
(case6 : motive_2 B.empty) (a✝ : A) : motive_1 a✝
|
||
-/
|
||
#guard_msgs in
|
||
#check A.size.induct
|
||
|
||
/--
|
||
info: A.subs.induct (motive_1 : A → Prop) (motive_2 : B → Prop) (case1 : ∀ (a : A), motive_1 a → motive_1 a.self)
|
||
(case2 : ∀ (b : B), motive_2 b → motive_1 (A.other b)) (case3 : motive_1 A.empty)
|
||
(case4 : ∀ (b : B), motive_2 b → motive_2 b.self) (case5 : ∀ (a : A), motive_1 a → motive_2 (B.other a))
|
||
(case6 : motive_2 B.empty) (a : A) : motive_1 a
|
||
-/
|
||
#guard_msgs in
|
||
#check A.subs.induct
|
||
|
||
/--
|
||
info: MutualIndNonMutualFun.A.self_size.induct (motive : MutualIndNonMutualFun.A → Prop)
|
||
(case1 : ∀ (a : MutualIndNonMutualFun.A), motive a → motive a.self)
|
||
(case2 : ∀ (a : MutualIndNonMutualFun.B), motive (MutualIndNonMutualFun.A.other a))
|
||
(case3 : motive MutualIndNonMutualFun.A.empty) (a✝ : MutualIndNonMutualFun.A) : motive a✝
|
||
-/
|
||
#guard_msgs in
|
||
#check MutualIndNonMutualFun.A.self_size.induct
|
||
|
||
/--
|
||
info: MutualIndNonMutualFun.A.self_size_with_param.induct (motive : Nat → MutualIndNonMutualFun.A → Prop)
|
||
(case1 : ∀ (n : Nat) (a : MutualIndNonMutualFun.A), motive n a → motive n a.self)
|
||
(case2 : ∀ (x : Nat) (a : MutualIndNonMutualFun.B), motive x (MutualIndNonMutualFun.A.other a))
|
||
(case3 : ∀ (x : Nat), motive x MutualIndNonMutualFun.A.empty) (a✝ : Nat) (a✝¹ : MutualIndNonMutualFun.A) :
|
||
motive a✝ a✝¹
|
||
-/
|
||
#guard_msgs in
|
||
#check MutualIndNonMutualFun.A.self_size_with_param.induct
|
||
|
||
/--
|
||
info: A.hasNoBEmpty.induct (motive_1 : A → Prop) (motive_2 : B → Prop) (case1 : ∀ (a : A), motive_1 a → motive_1 a.self)
|
||
(case2 : ∀ (b : B), motive_2 b → motive_1 (A.other b)) (case3 : motive_1 A.empty)
|
||
(case4 : ∀ (b : B), motive_2 b → motive_2 b.self) (case5 : ∀ (a : A), motive_1 a → motive_2 (B.other a))
|
||
(case6 : motive_2 B.empty) (a✝ : A) : motive_1 a✝
|
||
-/
|
||
#guard_msgs in
|
||
#check A.hasNoBEmpty.induct
|
||
|
||
/--
|
||
info: EvenOdd.isEven.induct (motive_1 motive_2 : Nat → Prop) (case1 : motive_1 0)
|
||
(case2 : ∀ (n : Nat), motive_2 n → motive_1 n.succ) (case3 : motive_2 0)
|
||
(case4 : ∀ (n : Nat), motive_1 n → motive_2 n.succ) (a✝ : Nat) : motive_1 a✝
|
||
-/
|
||
#guard_msgs in
|
||
#check EvenOdd.isEven.induct
|
||
|
||
/--
|
||
info: WithTuple.Tree.map.induct {α β : Type} (f : α → β) (motive_1 : WithTuple.Tree α → Prop)
|
||
(motive_2 : WithTuple.Tree α × WithTuple.Tree α → Prop)
|
||
(case1 :
|
||
∀ (x : α) (arrs : WithTuple.Tree α × WithTuple.Tree α), motive_2 arrs → motive_1 (WithTuple.Tree.node x arrs))
|
||
(case2 : ∀ (t₁ t₂ : WithTuple.Tree α), motive_1 t₁ → motive_1 t₂ → motive_2 (t₁, t₂)) (x : WithTuple.Tree α) :
|
||
motive_1 x
|
||
-/
|
||
#guard_msgs in
|
||
#check WithTuple.Tree.map.induct
|
||
|
||
/--
|
||
info: WithArray.Tree.map.induct {α β : Type} (f : α → β) (motive_1 : WithArray.Tree α → Prop)
|
||
(motive_2 : Array (WithArray.Tree α) → Prop) (motive_3 : List (WithArray.Tree α) → Prop)
|
||
(case1 : ∀ (x : α) (arr₁ : Array (WithArray.Tree α)), motive_2 arr₁ → motive_1 (WithArray.Tree.node x arr₁))
|
||
(case2 : ∀ (arr₁ : List (WithArray.Tree α)), motive_3 arr₁ → motive_2 { toList := arr₁ }) (case3 : motive_3 [])
|
||
(case4 : ∀ (h₁ : WithArray.Tree α) (t₁ : List (WithArray.Tree α)), motive_1 h₁ → motive_3 t₁ → motive_3 (h₁ :: t₁))
|
||
(x : WithArray.Tree α) : motive_1 x
|
||
-/
|
||
#guard_msgs in
|
||
#check WithArray.Tree.map.induct
|
||
|
||
end FunIndTests
|