feat: accurate binder names in signatures (like in output of #check) (#5827)

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
This commit is contained in:
Kyle Miller 2024-10-29 09:43:11 -07:00 committed by GitHub
parent 0d471513c5
commit cdbe29b46d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 269 additions and 191 deletions

View file

@ -228,14 +228,27 @@ def withAnnotateTermInfo (d : Delab) : Delab := do
let stx ← d
annotateTermInfo stx
def getUnusedName (suggestion : Name) (body : Expr) : DelabM Name := do
-- Use a nicer binder name than `[anonymous]`. We probably shouldn't do this in all LocalContext use cases, so do it here.
let suggestion := if suggestion.isAnonymous then `a else suggestion
-- We use this small hack to convert identifiers created using `mkAuxFunDiscr` to simple names
let suggestion := suggestion.eraseMacroScopes
/--
Gets an name based on `suggestion` that is unused in the local context.
Erases macro scopes.
If `pp.safeShadowing` is true, then the name is allowed to shadow a name in the local context
if the name does not appear in `body`.
If `preserveName` is false, then returns the name, possibly with fresh macro scopes added.
If `suggestion` has macro scopes then the result does as well.
-/
def getUnusedName (suggestion : Name) (body : Expr) (preserveName : Bool := false) : DelabM Name := do
let (hasScopes, suggestion) :=
if suggestion.isAnonymous then
-- Use a nicer binder name than `[anonymous]`. We probably shouldn't do this in all LocalContext use cases, so do it here.
(true, `a)
else
(suggestion.hasMacroScopes, suggestion.eraseMacroScopes)
let lctx ← getLCtx
if !lctx.usesUserName suggestion then
if !lctx.usesUserName suggestion || (preserveName && !hasScopes) then
return suggestion
else if preserveName then
withFreshMacroScope <| MonadQuotation.addMacroScope suggestion
else if (← getPPOption getPPSafeShadowing) && !bodyUsesSuggestion lctx suggestion then
return suggestion
else
@ -262,9 +275,12 @@ def mkAnnotatedIdent (n : Name) (e : Expr) : DelabM Ident := do
Enters the body of the current expression, which must be a lambda or forall.
The binding variable is passed to `d` as `Syntax`, and it is an identifier that has been annotated with the fvar expression
for the variable.
If `preserveName` is `false` (the default), gives the binder an unused name.
Otherwise, it tries to preserve the textual form of the name, preserving whether it is hygienic.
-/
def withBindingBodyUnusedName {α} (d : Syntax → DelabM α) : DelabM α := do
let n ← getUnusedName (← getExpr).bindingName! (← getExpr).bindingBody!
def withBindingBodyUnusedName {α} (d : Syntax → DelabM α) (preserveName := false) : DelabM α := do
let n ← getUnusedName (← getExpr).bindingName! (← getExpr).bindingBody! (preserveName := preserveName)
withBindingBody' n (mkAnnotatedIdent n) (d ·)
inductive OmissionReason

View file

@ -887,24 +887,31 @@ def delabLam : Delab :=
else
`(fun $binders* => $stxBody)
/-- Don't do any renaming for forall binders, but do add fresh macro scopes when there is shadowing. -/
private def ppPiPreserveNames := `pp.piPreserveNames
/-- Causes non-dependent foralls to print with binder names. -/
private def ppPiBinderNames := `pp.piBinderNames
/--
Similar to `delabBinders`, but tracking whether `forallE` is dependent or not.
See issue #1571
-/
private partial def delabForallBinders (delabGroup : Array Syntax → Bool → Syntax → Delab) (curNames : Array Syntax := #[]) (curDep := false) : Delab := do
let dep := !(← getExpr).isArrow
-- Logic note: wanting to print with binder names is equivalent to pretending the forall is dependent.
let dep := !(← getExpr).isArrow || (← getOptionsAtCurrPos).get ppPiBinderNames false
if !curNames.isEmpty && dep != curDep then
-- don't group
delabGroup curNames curDep (← delab)
else
let preserve := (← getOptionsAtCurrPos).get ppPiPreserveNames false
let curDep := dep
if ← shouldGroupWithNext then
-- group with nested binder => recurse immediately
withBindingBodyUnusedName fun stxN => delabForallBinders delabGroup (curNames.push stxN) curDep
withBindingBodyUnusedName (preserveName := preserve) fun stxN => delabForallBinders delabGroup (curNames.push stxN) curDep
else
-- don't group => delab body and prepend current binder group
let (stx, stxN) ← withBindingBodyUnusedName fun stxN => return (← delab, stxN)
let (stx, stxN) ← withBindingBodyUnusedName (preserveName := preserve) fun stxN => return (← delab, stxN)
delabGroup (curNames.push stxN) curDep stx
@[builtin_delab forallE]
@ -1297,11 +1304,13 @@ where
-- but this would be the usual case.
let group ← withBindingDomain do `(bracketedBinderF|[$(← delabTy)])
withBindingBody e.bindingName! <| delabParams bindingNames idStx (groups.push group)
else if e.isForall && !e.bindingName!.hasMacroScopes && !bindingNames.contains e.bindingName! then
else if e.isForall && (!e.isArrow || !(e.bindingName!.hasMacroScopes || bindingNames.contains e.bindingName!)) then
delabParamsAux bindingNames idStx groups #[]
else
let type ← delabTy
`(declSigWithId| $idStx:ident $groups* : $type)
let (opts', e') ← processSpine {} (← readThe SubExpr)
withReader (fun ctx => {ctx with optionsPerPos := opts', subExpr := { ctx.subExpr with expr := e' }}) do
let type ← delabTy
`(declSigWithId| $idStx:ident $groups* : $type)
/--
Inner loop for `delabParams`, collecting binders.
Invariants:
@ -1311,6 +1320,7 @@ where
-/
delabParamsAux (bindingNames : NameSet) (idStx : Ident) (groups : TSyntaxArray ``bracketedBinder) (curIds : Array Ident) := do
let e@(.forallE n d e' i) ← getExpr | unreachable!
let n ← if bindingNames.contains n then withFreshMacroScope <| MonadQuotation.addMacroScope n else pure n
let bindingNames := bindingNames.insert n
let stxN := mkIdent n
let curIds := curIds.push ⟨stxN⟩
@ -1336,13 +1346,34 @@ where
-/
shouldGroupWithNext (bindingNames : NameSet) (e e' : Expr) : Bool :=
e'.isForall &&
-- At the first sign of an inaccessible name, stop merging binders:
!e'.bindingName!.hasMacroScopes &&
-- If it's a name that has already been used, stop merging binders:
!bindingNames.contains e'.bindingName! &&
(!e'.isArrow ||
-- At the first sign of an inaccessible name, stop merging binders:
!(e'.bindingName!.hasMacroScopes ||
-- If it's a name that has already been used, stop merging binders:
bindingNames.contains e'.bindingName!)) &&
e.binderInfo == e'.binderInfo &&
e.bindingDomain! == e'.bindingDomain! &&
-- Inst implicits can't be grouped:
e'.binderInfo != BinderInfo.instImplicit
/--
Go through rest of type, alpha renaming and setting options along the spine.
-/
processSpine (opts : OptionsPerPos) (subExpr : SubExpr) : MetaM (OptionsPerPos × Expr) := do
if let .forallE n t b bi := subExpr.expr then
let used := (← getLCtx).usesUserName n
withLocalDecl n bi t fun fvar => do
let (opts, b') ← processSpine opts { expr := b.instantiate1 fvar, pos := subExpr.pos.pushBindingBody }
let b' := b'.abstract #[fvar]
let opts := opts.insertAt subExpr.pos ppPiPreserveNames true
if n.hasMacroScopes then
return (opts, .forallE n t b' bi)
else if !used then
let opts := opts.insertAt subExpr.pos ppPiBinderNames true
return (opts, .forallE n t b' bi)
else
let n' ← withFreshMacroScope <| MonadQuotation.addMacroScope n
return (opts, .forallE n' t b' bi)
else
return (opts, subExpr.expr)
end Lean.PrettyPrinter.Delaborator

View file

@ -18,6 +18,14 @@ namespace Lean.PrettyPrinter.Delaborator
abbrev OptionsPerPos := RBMap SubExpr.Pos Options compare
def OptionsPerPos.insertAt (optionsPerPos : OptionsPerPos) (pos : SubExpr.Pos) (name : Name) (value : DataValue) : OptionsPerPos :=
let opts := optionsPerPos.find? pos |>.getD {}
optionsPerPos.insert pos <| opts.insert name value
/-- Merges two collections of options, where the second overrides the first. -/
def OptionsPerPos.merge : OptionsPerPos → OptionsPerPos → OptionsPerPos :=
RBMap.mergeBy (fun _ => KVMap.mergeBy (fun _ _ dv => dv))
namespace SubExpr
open Lean.SubExpr

View file

@ -30,16 +30,18 @@ structure Context where
structure State where
stxTrav : Syntax.Traverser
-- Textual content of `stack` up to the first whitespace (not enclosed in an escaped ident). We assume that the textual
-- content of `stack` is modified only by `pushText` and `pushLine`, so `leadWord` is adjusted there accordingly.
/-- Textual content of `stack` up to the first whitespace (not enclosed in an escaped ident). We assume that the textual
content of `stack` is modified only by `pushText` and `pushLine`, so `leadWord` is adjusted there accordingly. -/
leadWord : String := ""
-- Whether the generated format begins with the result of an ungrouped category formatter.
/-- When the `leadWord` is nonempty, whether it is an identifier. Identifiers get space inserted between them. -/
leadWordIdent : Bool := false
/-- Whether the generated format begins with the result of an ungrouped category formatter. -/
isUngrouped : Bool := false
-- Whether the resulting format must be grouped when used in a category formatter.
-- If the flag is set to false, then categoryParser omits the fill+nest operation.
/-- Whether the resulting format must be grouped when used in a category formatter.
If the flag is set to false, then categoryParser omits the fill+nest operation. -/
mustBeGrouped : Bool := true
-- Stack of generated Format objects, analogous to the Syntax stack in the parser.
-- Note, however, that the stack is reversed because of the right-to-left traversal.
/-- Stack of generated Format objects, analogous to the Syntax stack in the parser.
Note, however, that the stack is reversed because of the right-to-left traversal. -/
stack : Array Format := #[]
end Formatter
@ -121,7 +123,7 @@ private def push (f : Format) : FormatterM Unit :=
def pushWhitespace (f : Format) : FormatterM Unit := do
push f
modify fun st => { st with leadWord := "", isUngrouped := false }
modify fun st => { st with leadWord := "", leadWordIdent := false, isUngrouped := false }
def pushLine : FormatterM Unit :=
pushWhitespace Format.line
@ -335,7 +337,7 @@ def parseToken (s : String) : FormatterM ParserState :=
options := ← getOptions
} ((← read).table) (Parser.mkParserState s)
def pushToken (info : SourceInfo) (tk : String) : FormatterM Unit := do
def pushToken (info : SourceInfo) (tk : String) (ident : Bool) : FormatterM Unit := do
match info with
| SourceInfo.original _ _ ss _ =>
-- preserve non-whitespace content (i.e. comments)
@ -346,23 +348,34 @@ def pushToken (info : SourceInfo) (tk : String) : FormatterM Unit := do
push s!"\n{ss'}"
else
push s!" {ss'}"
modify fun st => { st with leadWord := "" }
modify fun st => { st with leadWord := "", leadWordIdent := false }
| _ => pure ()
let st ← get
-- If there is no space between `tk` and the next word, see if we would parse more than `tk` as a single token
-- If there is no space between `tk` and the next word, see if we should insert a discretionary space.
if st.leadWord != "" && tk.trimRight == tk then
let tk' := tk.trimLeft
let t ← parseToken $ tk' ++ st.leadWord
if t.pos <= tk'.endPos then
-- stopped within `tk` => use it as is, extend `leadWord` if not prefixed by whitespace
let insertSpace ← do
if ident && st.leadWordIdent then
-- Both idents => need space
pure true
else
-- Check if we would parse more than `tk` as a single token
let tk' := tk.trimLeft
let t ← parseToken $ tk' ++ st.leadWord
if t.pos ≤ tk'.endPos then
-- stopped within `tk` => use it as is
pure false
else
-- stopped after `tk` => add space
pure true
if !insertSpace then
-- extend `leadWord` if not prefixed by whitespace
push tk
modify fun st => { st with leadWord := if tk.trimLeft == tk then tk ++ st.leadWord else "" }
modify fun st => { st with leadWord := if tk.trimLeft == tk then tk ++ st.leadWord else "", leadWordIdent := ident }
else
-- stopped after `tk` => add space
pushLine
push tk
modify fun st => { st with leadWord := if tk.trimLeft == tk then tk else "" }
modify fun st => { st with leadWord := if tk.trimLeft == tk then tk else "", leadWordIdent := ident }
else
-- already separated => use `tk` as is
if st.leadWord == "" then
@ -372,7 +385,7 @@ def pushToken (info : SourceInfo) (tk : String) : FormatterM Unit := do
push tk.trimRight
else
push tk -- preserve special whitespace for tokens like ":=\n"
modify fun st => { st with leadWord := if tk.trimLeft == tk then tk else "" }
modify fun st => { st with leadWord := if tk.trimLeft == tk then tk else "", leadWordIdent := ident }
match info with
| SourceInfo.original ss _ _ _ =>
@ -395,7 +408,7 @@ def symbolNoAntiquot.formatter (sym : String) : Formatter := do
let stx ← getCur
if stx.isToken sym then do
let (Syntax.atom info _) ← pure stx | unreachable!
withMaybeTag (getExprPos? stx) (pushToken info sym)
withMaybeTag (getExprPos? stx) (pushToken info sym false)
goLeft
else do
trace[PrettyPrinter.format.backtrack] "unexpected syntax '{format stx}', expected symbol '{sym}'"
@ -410,9 +423,9 @@ def unicodeSymbolNoAntiquot.formatter (sym asciiSym : String) : Formatter := do
let Syntax.atom info val ← getCur
| throwError m!"not an atom: {← getCur}"
if val == sym.trim then
pushToken info sym
pushToken info sym false
else
pushToken info asciiSym;
pushToken info asciiSym false
goLeft
@[combinator_formatter identNoAntiquot]
@ -423,14 +436,14 @@ def identNoAntiquot.formatter : Formatter := do
let id := id.simpMacroScopes
let table := (← read).table
let isToken (s : String) : Bool := (table.find? s).isSome
withMaybeTag (getExprPos? stx) (pushToken info (id.toString (isToken := isToken)))
withMaybeTag (getExprPos? stx) (pushToken info (id.toString (isToken := isToken)) true)
goLeft
@[combinator_formatter rawIdentNoAntiquot] def rawIdentNoAntiquot.formatter : Formatter := do
checkKind identKind
let Syntax.ident info _ id _ ← getCur
| throwError m!"not an ident: {← getCur}"
pushToken info id.toString
pushToken info id.toString true
goLeft
@[combinator_formatter identEq] def identEq.formatter (_id : Name) := rawIdentNoAntiquot.formatter
@ -441,7 +454,7 @@ def visitAtom (k : SyntaxNodeKind) : Formatter := do
checkKind k
let Syntax.atom info val ← pure $ stx.ifNode (fun n => n.getArg 0) (fun _ => stx)
| throwError m!"not an atom: {stx}"
pushToken info val
pushToken info val false
goLeft
@[combinator_formatter charLitNoAntiquot] def charLitNoAntiquot.formatter := visitAtom charLitKind
@ -490,7 +503,7 @@ def sepByNoAntiquot.formatter (p pSep : Formatter) : Formatter := do
@[combinator_formatter checkStackTop] def checkStackTop.formatter : Formatter := pure ()
@[combinator_formatter checkNoWsBefore] def checkNoWsBefore.formatter : Formatter :=
-- prevent automatic whitespace insertion
modify fun st => { st with leadWord := "" }
modify fun st => { st with leadWord := "", leadWordIdent := false }
@[combinator_formatter checkLinebreakBefore] def checkLinebreakBefore.formatter : Formatter := pure ()
@[combinator_formatter checkTailWs] def checkTailWs.formatter : Formatter := pure ()
@[combinator_formatter checkColEq] def checkColEq.formatter : Formatter := pure ()

View file

@ -161,7 +161,7 @@ open Formatter Syntax.MonadTraverser in
let .atom info val := stx
| trace[PrettyPrinter.format.backtrack] "unexpected syntax '{format stx}', expected atom"
throwBacktrack
withMaybeTag (getSyntaxExprPos? stx) (pushToken info val)
withMaybeTag (getSyntaxExprPos? stx) (pushToken info val false)
goLeft
@[combinator_parenthesizer atom]

View file

@ -3,4 +3,4 @@ case nil
α✝ : Type u_1
as : List α✝
⊢ Palindrome [].reverse
palindrome_reverse.{u_1} : ∀ {α : Type u_1} {as : List α}, Palindrome as → Palindrome as.reverse
palindrome_reverse.{u_1} {α✝ : Type u_1} {as : List α✝} (h : Palindrome as) : Palindrome as.reverse

View file

@ -46,6 +46,6 @@ fun x =>
| #[] => 0
| #[3, 4, 5] => 3
| x => 4 : Array Nat → Nat
g.match_1.{u_1, u_2} {α : Type u_1} (motive : List α → Sort u_2) :
(x : List α) → ((a : α) → motive [a]) → ((x : List α) → motive x) → motive x
g.match_1.{u_1, u_2} {α : Type u_1} (motive : List α → Sort u_2) (x✝ : List α) (h_1 : (a : α) → motive [a])
(h_2 : (x : List α) → motive x) : motive x✝
fun e => nomatch e : Empty → False

View file

@ -30,31 +30,41 @@ def Nat.pos_pow_of_pos' {n : Nat} (m : Nat) : 0 < n → 0 < n ^ m := Nat.pos_pow
/-!
Repetition of a named argument, only the first is printed as a named argument.
The second is made hygienic.
-/
def foo (n n : Nat) : Fin (n + 1) := 0
/-- info: foo (n : Nat) : (n : Nat) → Fin (n + 1) -/
/-- info: foo (n n✝ : Nat) : Fin (n✝ + 1) -/
#guard_msgs in #check foo
/-!
Repetition of a named argument, only the first is printed as a named argument.
This is checking that shadowing is handled correctly (that's not the responsibility of
`delabConstWithSignature`, but it assumes that the main delaborator will handle this correctly).
Same, but a named argument still follows, and its name is preserved.
-/
def foo' (n n : Nat) (a : Fin ((by clear n; exact n) + 1)) : Fin (n + 1) := 0
/-- info: foo' (n : Nat) : (n_1 : Nat) → Fin (n + 1) → Fin (n_1 + 1) -/
/-- info: foo' (n n✝ : Nat) (a : Fin (n + 1)) : Fin (n✝ + 1) -/
#guard_msgs in #check foo'
/-!
Named argument after inaccessible name, still stays after the colon.
But, it does not print using named pi notation since this is not a dependent type.
Named argument after non-dependent inaccessible name, still stays after the colon.
Prints with named pi notation.
-/
def foo'' : String → (needle : String) → String := fun _ yo => yo
/-- info: foo'' : String → String → String -/
/-- info: foo'' : String → (needle : String) → String -/
#guard_msgs in #check foo''
/-!
Named argument after inaccessible name that's still a dependent argument.
Stays before the colon, and the names are grouped.
-/
def foo''' : (_ : Nat) → (n : Nat) → Fin (n + by clear n; assumption) := sorry
/-- info: foo''' (x✝ n : Nat) : Fin (n + x✝) -/
#guard_msgs in #check foo'''
/-!
Named argument after inaccessible name, still stays after the colon.
Here, because it's a dependent type the named pi notation shows the name.

View file

@ -8,7 +8,7 @@ def many_map {α β : Type} (f : α → β) : Many α → Many β
/--
info: many_map.induct {α β : Type} (f : α → β) (motive : Many α → Prop) (case1 : motive Many.none)
(case2 : ∀ (x : α) (xs : Unit → Many α), motive (xs ()) → motive (Many.more x xs)) : ∀ (a : Many α), motive a
(case2 : ∀ (x : α) (xs : Unit → Many α), motive (xs ()) → motive (Many.more x xs)) (a✝ : Many α) : motive a✝
-/
#guard_msgs in
#check many_map.induct

View file

@ -1,3 +1,4 @@
import Lean
/-!
# Long runs of identifiers should include line breaks
-/
@ -19,3 +20,12 @@ info: foo
Nat
-/
#guard_msgs(whitespace := exact) in #check foo
/-!
Issue pointed out by Mario: need spaces between `x✝` and `y✝`.
-/
/--
info: def foo✝ (x✝ y✝ : Nat✝) :=
x✝
-/
#guard_msgs in #eval do Lean.PrettyPrinter.ppCommand (← `(command| def foo (x y : Nat) := x))

View file

@ -11,24 +11,23 @@ def Formula.count_quantifiers : {n:Nat} → Formula n → Nat
attribute [simp] Formula.count_quantifiers
/--
info: Formula.count_quantifiers.eq_1.{u_1} :
∀ (x : Nat) (f₁ f₂ : Formula x), (f₁.imp f₂).count_quantifiers = f₁.count_quantifiers + f₂.count_quantifiers
info: Formula.count_quantifiers.eq_1.{u_1} (x✝ : Nat) (f₁ f₂ : Formula x✝) :
(f₁.imp f₂).count_quantifiers = f₁.count_quantifiers + f₂.count_quantifiers
-/
#guard_msgs in
#check Formula.count_quantifiers.eq_1
/--
info: Formula.count_quantifiers.eq_2.{u_1} :
∀ (x : Nat) (f : Formula (x + 1)), f.all.count_quantifiers = f.count_quantifiers + 1
info: Formula.count_quantifiers.eq_2.{u_1} (x✝ : Nat) (f : Formula (x✝ + 1)) :
f.all.count_quantifiers = f.count_quantifiers + 1
-/
#guard_msgs in
#check Formula.count_quantifiers.eq_2
/--
info: Formula.count_quantifiers.eq_3.{u_1} :
∀ (x : Nat) (x_1 : Formula x),
(∀ (f₁ f₂ : Formula x), x_1 = f₁.imp f₂ → False) →
(∀ (f : Formula (x + 1)), x_1 = f.all → False) → x_1.count_quantifiers = 0
info: Formula.count_quantifiers.eq_3.{u_1} (x✝ : Nat) (x✝¹ : Formula x✝)
(x_4 : ∀ (f₁ f₂ : Formula x✝), x✝¹ = f₁.imp f₂ → False) (x_5 : ∀ (f : Formula (x✝ + 1)), x✝¹ = f.all → False) :
x✝¹.count_quantifiers = 0
-/
#guard_msgs in
#check Formula.count_quantifiers.eq_3

View file

@ -11,13 +11,13 @@ def foo : Bool → Nat → Nat
| _, n+1 => foo .false n
termination_by _ n => n
/-- info: foo.eq_1 : ∀ (x : Bool), foo x 0 = 0 -/
/-- info: foo.eq_1 (x✝ : Bool) : foo x✝ 0 = 0 -/
#guard_msgs in
#check foo.eq_1
/-- info: foo.eq_2 (n : Nat) : foo true n.succ = foo true n -/
#guard_msgs in
#check foo.eq_2
/-- info: foo.eq_3 : ∀ (x : Bool) (n : Nat), (x = true → False) → foo x n.succ = foo false n -/
/-- info: foo.eq_3 (x✝ : Bool) (n : Nat) (x_3 : x✝ = true → False) : foo x✝ n.succ = foo false n -/
#guard_msgs in
#check foo.eq_3

View file

@ -8,8 +8,8 @@ def ackermann : Nat → Nat → Nat
/--
info: ackermann.induct (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
(case2 : ∀ (n : Nat), motive n 1 → motive n.succ 0)
(case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive n.succ m.succ) :
∀ (a a_1 : Nat), motive a a_1
(case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive n.succ m.succ) (a✝ a✝¹ : Nat) :
motive a✝ a✝¹
-/
#guard_msgs in
#check ackermann.induct
@ -19,7 +19,7 @@ def Tree.rev : Tree → Tree | node ts => .node (ts.attach.map (fun ⟨t, _ht⟩
/--
info: Tree.rev.induct (motive : Tree → Prop)
(case1 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive t) → motive (Tree.node ts)) : ∀ (a : Tree), motive a
(case1 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive t) → motive (Tree.node ts)) (a✝ : Tree) : motive a✝
-/
#guard_msgs in
#check Tree.rev.induct

View file

@ -10,8 +10,8 @@ def foo.{u} : Nat → PUnit.{u}
| n+1 => foo n
/--
info: Structural.foo.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) :
∀ (a : Nat), motive a
info: Structural.foo.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ)
(a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check foo.induct
@ -31,7 +31,7 @@ termination_by xs => xs
/--
info: WellFounded.foo.induct.{v} {α : Type v} (motive : List α → Prop) (case1 : motive [])
(case2 : ∀ (head : α) (xs : List α), motive xs → motive (head :: xs)) : ∀ (a : List α), motive a
(case2 : ∀ (head : α) (xs : List α), motive xs → motive (head :: xs)) (a✝ : List α) : motive a✝
-/
#guard_msgs in
#check foo.induct
@ -58,7 +58,7 @@ end
/--
info: Mutual.foo.induct (motive1 motive2 : Nat → Prop) (case1 : motive1 0) (case2 : ∀ (n : Nat), motive2 n → motive1 n.succ)
(case3 : motive2 0) (case4 : ∀ (n : Nat), motive1 n → motive2 n.succ) : ∀ (a : Nat), motive1 a
(case3 : motive2 0) (case4 : ∀ (n : Nat), motive1 n → motive2 n.succ) (a✝ : Nat) : motive1 a✝
-/
#guard_msgs in
#check foo.induct

View file

@ -35,7 +35,7 @@ info: Term.replaceConst.induct (a b : String) (motive1 : Term → Prop) (motive2
(case1 : ∀ (a_1 : String), (a == a_1) = true → motive1 (const a_1))
(case2 : ∀ (a_1 : String), ¬(a == a_1) = true → motive1 (const a_1))
(case3 : ∀ (a : String) (cs : List Term), motive2 cs → motive1 (app a cs)) (case4 : motive2 [])
(case5 : ∀ (c : Term) (cs : List Term), motive1 c → motive2 cs → motive2 (c :: cs)) : ∀ (a : Term), motive1 a
(case5 : ∀ (c : Term) (cs : List Term), motive1 c → motive2 cs → motive2 (c :: cs)) (a✝ : Term) : motive1 a✝
-/
#guard_msgs in
#check replaceConst.induct

View file

@ -11,7 +11,7 @@ termination_by structural x => x
/--
info: fib.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 1)
(case3 : ∀ (n : Nat), motive n → motive (n + 1) → motive n.succ.succ) : ∀ (a : Nat), motive a
(case3 : ∀ (n : Nat), motive n → motive (n + 1) → motive n.succ.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check fib.induct
@ -24,8 +24,8 @@ termination_by structural x => x
/--
info: binary.induct (motive : Nat → Nat → Prop) (case1 : ∀ (acc : Nat), motive 0 acc) (case2 : ∀ (acc : Nat), motive 1 acc)
(case3 : ∀ (n acc : Nat), motive (n + 1) acc → motive n (binary (n + 1) acc) → motive n.succ.succ acc) :
∀ (a a_1 : Nat), motive a a_1
(case3 : ∀ (n acc : Nat), motive (n + 1) acc → motive n (binary (n + 1) acc) → motive n.succ.succ acc)
(a✝ a✝¹ : Nat) : motive a✝ a✝¹
-/
#guard_msgs in
#check binary.induct
@ -40,8 +40,8 @@ termination_by structural _ x => x
/--
info: binary'.induct (motive : Bool → Nat → Prop) (case1 : ∀ (acc : Bool), motive acc 0)
(case2 : ∀ (acc : Bool), motive acc 1)
(case3 : ∀ (acc : Bool) (n : Nat), motive acc (n + 1) → motive (binary' acc (n + 1)) n → motive acc n.succ.succ) :
∀ (a : Bool) (a_1 : Nat), motive a a_1
(case3 : ∀ (acc : Bool) (n : Nat), motive acc (n + 1) → motive (binary' acc (n + 1)) n → motive acc n.succ.succ)
(a✝ : Bool) (a✝¹ : Nat) : motive a✝ a✝¹
-/
#guard_msgs in
#check binary'.induct
@ -55,8 +55,8 @@ termination_by structural x => x
/--
info: zip.induct.{u_1, u_2} {α : Type u_1} {β : Type u_2} (motive : List α → List β → Prop)
(case1 : ∀ (x : List β), motive [] x) (case2 : ∀ (t : List α), (t = [] → False) → motive t [])
(case3 : ∀ (x : α) (xs : List α) (y : β) (ys : List β), motive xs ys → motive (x :: xs) (y :: ys)) :
∀ (a : List α) (a_1 : List β), motive a a_1
(case3 : ∀ (x : α) (xs : List α) (y : β) (ys : List β), motive xs ys → motive (x :: xs) (y :: ys)) (a✝ : List α)
(a✝¹ : List β) : motive a✝ a✝¹
-/
#guard_msgs in
#check zip.induct
@ -94,7 +94,7 @@ info: Finn.min.induct (motive : Bool → {n : Nat} → Nat → Finn n → Finn n
(case1 : ∀ (x : Bool) (m n : Nat) (x_1 : Finn n), motive x m Finn.fzero x_1)
(case2 : ∀ (x : Bool) (m n : Nat) (x_1 : Finn n), (x_1 = Finn.fzero → False) → motive x m x_1 Finn.fzero)
(case3 : ∀ (x : Bool) (m n : Nat) (i j : Finn n), motive (!x) (m + 1) i j → motive x m i.fsucc j.fsucc) (x : Bool)
{n : Nat} (m : Nat) : ∀ (a f : Finn n), motive x m a f
{n : Nat} (m : Nat) (a✝ f : Finn n) : motive x m a✝ f
-/
#guard_msgs in
#check Finn.min.induct
@ -195,7 +195,7 @@ info: TermDenote.Term.denote.induct (motive : {ctx : List Ty} → {ty : Ty} →
(case6 :
∀ (a : List Ty) (ty ty₁ : Ty) (a_1 : Term a ty₁) (b : Term (ty₁ :: a) ty) (env : HList Ty.denote a),
motive a_1 env → motive b (HList.cons (a_1.denote env) env) → motive (a_1.let b) env)
{ctx : List Ty} {ty : Ty} : ∀ (a : Term ctx ty) (a_1 : HList Ty.denote ctx), motive a a_1
{ctx : List Ty} {ty : Ty} (a✝ : Term ctx ty) (a✝¹ : HList Ty.denote ctx) : motive a✝ a✝¹
-/
#guard_msgs in
#check TermDenote.Term.denote.induct

View file

@ -25,8 +25,8 @@ end
info: Tree.size.induct.{u_1} {α : Type u_1} (motive_1 : Tree α → Prop) (motive_2 : List (Tree α) → Prop)
(case1 :
∀ (a : α) (tsf : Bool → List (Tree α)), motive_2 (tsf true) → motive_2 (tsf false) → motive_1 (Tree.node a tsf))
(case2 : motive_2 []) (case3 : ∀ (t : Tree α) (ts : List (Tree α)), motive_1 t → motive_2 ts → motive_2 (t :: ts)) :
∀ (a : Tree α), motive_1 a
(case2 : motive_2 []) (case3 : ∀ (t : Tree α) (ts : List (Tree α)), motive_1 t → motive_2 ts → motive_2 (t :: ts))
(a✝ : Tree α) : motive_1 a✝
-/
#guard_msgs in
#check Tree.size.induct

View file

@ -15,8 +15,8 @@ termination_by p => p
/--
info: Unary.ackermann.induct (motive : Nat × Nat → Prop) (case1 : ∀ (m : Nat), motive (0, m))
(case2 : ∀ (n : Nat), motive (n, 1) → motive (n.succ, 0))
(case3 : ∀ (n m : Nat), motive (n + 1, m) → motive (n, ackermann (n + 1, m)) → motive (n.succ, m.succ)) :
∀ (a : Nat × Nat), motive a
(case3 : ∀ (n m : Nat), motive (n + 1, m) → motive (n, ackermann (n + 1, m)) → motive (n.succ, m.succ))
(a✝ : Nat × Nat) : motive a✝
-/
#guard_msgs in
#check ackermann.induct
@ -34,8 +34,8 @@ termination_by n m => (n, m)
/--
info: Binary.ackermann.induct (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
(case2 : ∀ (n : Nat), motive n 1 → motive n.succ 0)
(case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive n.succ m.succ) :
∀ (a a_1 : Nat), motive a a_1
(case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive n.succ m.succ) (a✝ a✝¹ : Nat) :
motive a✝ a✝¹
-/
#guard_msgs in
#check ackermann.induct
@ -50,7 +50,7 @@ def Tree.rev : Tree → Tree
/--
info: Tree.rev.induct (motive : Tree → Prop)
(case1 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive t) → motive (Tree.node ts)) : ∀ (a : Tree), motive a
(case1 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive t) → motive (Tree.node ts)) (a✝ : Tree) : motive a✝
-/
#guard_msgs in
#check Tree.rev.induct
@ -64,7 +64,7 @@ termination_by n => n
/--
info: fib.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 1)
(case3 : ∀ (n : Nat), motive n → motive (n + 1) → motive n.succ.succ) : ∀ (a : Nat), motive a
(case3 : ∀ (n : Nat), motive n → motive (n + 1) → motive n.succ.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check fib.induct
@ -78,8 +78,8 @@ def have_tailrec : Nat → Nat
termination_by n => n
/--
info: have_tailrec.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), n < n + 1 → motive n → motive n.succ) : ∀ (a : Nat), motive a
info: have_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), n < n + 1 → motive n → motive n.succ)
(a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check have_tailrec.induct
@ -94,8 +94,8 @@ def have_non_tailrec : Nat → Nat
termination_by n => n
/--
info: have_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) :
∀ (a : Nat), motive a
info: have_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ)
(a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check have_non_tailrec.induct
@ -109,8 +109,8 @@ def let_tailrec : Nat → Nat
termination_by n => n
/--
info: let_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) :
∀ (a : Nat), motive a
info: let_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) (a✝ : Nat) :
motive a
-/
#guard_msgs in
#check let_tailrec.induct
@ -125,8 +125,8 @@ def let_non_tailrec : Nat → Nat
termination_by n => n
/--
info: let_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) :
∀ (a : Nat), motive a
info: let_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ)
(a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check let_non_tailrec.induct
@ -145,7 +145,7 @@ termination_by n => n
/--
info: with_ite_tailrec.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), n % 2 = 0 → motive n → motive n.succ)
(case3 : ∀ (n : Nat), ¬n % 2 = 0 → motive n → motive n.succ) : ∀ (a : Nat), motive a
(case3 : ∀ (n : Nat), ¬n % 2 = 0 → motive n → motive n.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check with_ite_tailrec.induct
@ -165,7 +165,7 @@ termination_by n => n
/--
info: with_ite_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 1)
(case3 : ∀ (n : Nat), motive (n + 1) → motive n → motive n.succ.succ) : ∀ (a : Nat), motive a
(case3 : ∀ (n : Nat), motive (n + 1) → motive n → motive n.succ.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check with_ite_non_tailrec.induct
@ -212,7 +212,7 @@ termination_by n => n
/--
info: with_match_refining_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 0 → motive (Nat.succ 0))
(case3 : ∀ (m : Nat), (m = 0 → False) → motive m → motive m.succ) : ∀ (a : Nat), motive a
(case3 : ∀ (m : Nat), (m = 0 → False) → motive m → motive m.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check with_match_refining_tailrec.induct
@ -228,7 +228,7 @@ termination_by i
/--
info: with_arg_refining_match1.induct (motive : Nat → Nat → Prop) (case1 : ∀ (i : Nat), motive i 0)
(case2 : ∀ (n : Nat), motive 0 n.succ) (case3 : ∀ (i n : Nat), ¬i = 0 → motive (i - 1) n → motive i n.succ)
(i : Nat) : ∀ (a : Nat), motive i a
(i a✝ : Nat) : motive i a
-/
#guard_msgs in
#check with_arg_refining_match1.induct
@ -260,7 +260,7 @@ termination_by n => n
/--
info: with_other_match_tailrec.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), n % 2 = 0 → motive n → motive n.succ)
(case3 : ∀ (n : Nat), (n % 2 = 0 → False) → motive n → motive n.succ) : ∀ (a : Nat), motive a
(case3 : ∀ (n : Nat), (n % 2 = 0 → False) → motive n → motive n.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check with_other_match_tailrec.induct
@ -274,8 +274,8 @@ termination_by n => n
/--
info: with_mixed_match_tailrec.induct (motive : Nat → Nat → Nat → Nat → Prop) (case1 : ∀ (a a_1 x : Nat), motive 0 x a a_1)
(case2 : ∀ (a a_1 a_2 x : Nat), motive a_2 x (a % 2) (a_1 % 2) → motive a_2.succ x a a_1) :
∀ (a a_1 a_2 a_3 : Nat), motive a a_1 a_2 a_3
(case2 : ∀ (a a_1 a_2 x : Nat), motive a_2 x (a % 2) (a_1 % 2) → motive a_2.succ x a a_1) (a✝ a✝¹ a✝² a✝³ : Nat) :
motive a✝ a✝¹ a✝² a✝³
-/
#guard_msgs in
#check with_mixed_match_tailrec.induct
@ -293,8 +293,8 @@ termination_by n => n
/--
info: with_mixed_match_tailrec2.induct (motive : Nat → Nat → Nat → Nat → Nat → Prop)
(case1 : ∀ (a a_1 a_2 a_3 : Nat), motive 0 a a_1 a_2 a_3) (case2 : ∀ (a a_1 n x : Nat), motive n.succ 0 x a a_1)
(case3 : ∀ (a a_1 n a_2 x : Nat), motive n a_2 x (a % 2) (a_1 % 2) → motive n.succ a_2.succ x a a_1) :
∀ (a a_1 a_2 a_3 a_4 : Nat), motive a a_1 a_2 a_3 a_4
(case3 : ∀ (a a_1 n a_2 x : Nat), motive n a_2 x (a % 2) (a_1 % 2) → motive n.succ a_2.succ x a a_1)
(a✝ a✝¹ a✝² a✝³ a✝⁴ : Nat) : motive a✝ a✝¹ a✝² a✝³ a✝⁴
-/
#guard_msgs in
#check with_mixed_match_tailrec2.induct
@ -310,8 +310,8 @@ def with_match_non_tailrec : Nat → Nat
termination_by n => n
/--
info: with_match_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ) :
∀ (a : Nat), motive a
info: with_match_non_tailrec.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : ∀ (n : Nat), motive n → motive n.succ)
(a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check with_match_non_tailrec.induct
@ -333,8 +333,8 @@ info: with_match_non_tailrec_refining.induct (motive : Nat → Prop) (case1 : mo
(match n with
| 0 => motive 0
| m => motive m) →
motive n.succ) :
∀ (a : Nat), motive a
motive n.succ)
(a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check with_match_non_tailrec_refining.induct
@ -350,8 +350,8 @@ termination_by n => n
/--
info: with_overlap.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : motive 1) (case3 : motive 2) (case4 : motive 3)
(case5 : ∀ (n : Nat), (n = 0 → False) → (n = 1 → False) → (n = 2 → False) → motive n → motive n.succ) :
∀ (a : Nat), motive a
(case5 : ∀ (n : Nat), (n = 0 → False) → (n = 1 → False) → (n = 2 → False) → motive n → motive n.succ) (a✝ : Nat) :
motive a
-/
#guard_msgs in
#check with_overlap.induct
@ -368,7 +368,7 @@ termination_by n => n
/--
info: UnusedExtraParams.unary.induct (base : Nat) (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), motive n → motive n.succ) : ∀ (a : Nat), motive a
(case2 : ∀ (n : Nat), motive n → motive n.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check unary.induct
@ -380,7 +380,7 @@ termination_by n => n
/--
info: UnusedExtraParams.binary.induct (base : Nat) (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
(case2 : ∀ (n m : Nat), motive n m → motive n.succ m) : ∀ (a a_1 : Nat), motive a a_1
(case2 : ∀ (n m : Nat), motive n m → motive n.succ m) (a✝ a✝¹ : Nat) : motive a✝ a✝¹
-/
#guard_msgs in
#check binary.induct
@ -512,7 +512,7 @@ def foo {α} (x : α) : List α → Nat
termination_by xs => xs
/--
info: LetFun.foo.induct.{u_1} {α : Type u_1} (x : α) (motive : List α → Prop) (case1 : motive [])
(case2 : ∀ (_y : α) (ys : List α), motive ys → motive (_y :: ys)) : ∀ (a : List α), motive a
(case2 : ∀ (_y : α) (ys : List α), motive ys → motive (_y :: ys)) (a✝ : List α) : motive a✝
-/
#guard_msgs in
#check foo.induct
@ -527,7 +527,7 @@ termination_by xs => xs
/--
info: LetFun.bar.induct.{u_1} {α : Type u_1} (x : α) (motive : List α → Prop) (case1 : motive [])
(case2 : ∀ (_y : α) (ys : List α), Nat → motive ys → motive (_y :: ys)) : ∀ (a : List α), motive a
(case2 : ∀ (_y : α) (ys : List α), Nat → motive ys → motive (_y :: ys)) (a✝ : List α) : motive a✝
-/
#guard_msgs in
#check bar.induct
@ -545,7 +545,7 @@ termination_by n => n
/--
info: RecCallInDisrs.foo.induct (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), foo n = 0 → motive n → motive n.succ)
(case3 : ∀ (n : Nat), ¬foo n = 0 → motive n → motive n.succ) : ∀ (a : Nat), motive a
(case3 : ∀ (n : Nat), ¬foo n = 0 → motive n → motive n.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check foo.induct
@ -563,7 +563,7 @@ termination_by n => n
/--
info: RecCallInDisrs.bar.induct (motive : Nat → Prop) (case1 : motive 0) (case2 : bar 0 = 0 → motive 0 → motive (Nat.succ 0))
(case3 : (bar 0 = 0 → False) → motive 0 → motive (Nat.succ 0))
(case4 : ∀ (m : Nat), motive m.succ → motive m → motive m.succ.succ) : ∀ (a : Nat), motive a
(case4 : ∀ (m : Nat), motive m.succ → motive m → motive m.succ.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check bar.induct
@ -585,14 +585,14 @@ end
/--
info: EvenOdd.even.induct (motive1 motive2 : Nat → Prop) (case1 : motive1 0) (case2 : ∀ (n : Nat), motive2 n → motive1 n.succ)
(case3 : motive2 0) (case4 : ∀ (n : Nat), motive1 n → motive2 n.succ) : ∀ (a : Nat), motive1 a
(case3 : motive2 0) (case4 : ∀ (n : Nat), motive1 n → motive2 n.succ) (a✝ : Nat) : motive1 a✝
-/
#guard_msgs in
#check even.induct
/--
info: EvenOdd.odd.induct (motive1 motive2 : Nat → Prop) (case1 : motive1 0) (case2 : ∀ (n : Nat), motive2 n → motive1 n.succ)
(case3 : motive2 0) (case4 : ∀ (n : Nat), motive1 n → motive2 n.succ) : ∀ (a : Nat), motive2 a
(case3 : motive2 0) (case4 : ∀ (n : Nat), motive1 n → motive2 n.succ) (a✝ : Nat) : motive2 a✝
-/
#guard_msgs in
#check odd.induct
@ -615,7 +615,7 @@ end
/--
info: Tree.Tree.map.induct (f : Tree → Tree) (motive1 : Tree → Prop) (motive2 : List Tree → Prop)
(case1 : ∀ (ts : List Tree), motive2 ts → motive1 (Tree.node ts))
(case2 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive1 t) → motive2 ts) : ∀ (a : Tree), motive1 a
(case2 : ∀ (ts : List Tree), (∀ (t : Tree), t ∈ ts → motive1 t) → motive2 ts) (a✝ : Tree) : motive1 a✝
-/
#guard_msgs in
#check Tree.map.induct
@ -686,8 +686,8 @@ info: Nary.foo.induct (motive : Nat → Nat → (k : Nat) → Fin k → Prop) (c
(case2 : ∀ (k x : Nat), (x = 0 → False) → ∀ (x_2 : Fin k), motive x 0 k x_2)
(case3 : ∀ (x x_1 : Nat), (x = 0 → False) → (x_1 = 0 → False) → ∀ (a : Fin 0), motive x x_1 0 a)
(case4 : ∀ (x x_1 : Nat), (x = 0 → False) → (x_1 = 0 → False) → ∀ (a : Fin 1), motive x x_1 1 a)
(case5 : ∀ (n m k : Nat) (a : Fin k.succ.succ), motive n m (k + 1) ⟨0, ⋯⟩ → motive n.succ m.succ k.succ.succ a) :
∀ (a a_1 k : Nat) (a_2 : Fin k), motive a a_1 k a_2
(case5 : ∀ (n m k : Nat) (a : Fin k.succ.succ), motive n m (k + 1) ⟨0, ⋯⟩ → motive n.succ m.succ k.succ.succ a)
(a✝ a✝¹ k : Nat) (a✝² : Fin k) : motive a✝ a✝¹ k a✝²
-/
#guard_msgs in
#check foo.induct
@ -739,7 +739,7 @@ termination_by n => n
/--
info: PreserveParams.foo.induct (a : Nat) (motive : Nat → Prop) (case1 : motive 0)
(case2 : ∀ (n : Nat), a = 23 → motive n.succ) (case3 : ¬a = 23 → motive a.succ)
(case4 : ∀ (n : Nat), ¬a = 23 → ¬a = n → motive n → motive n.succ) : ∀ (a : Nat), motive a
(case4 : ∀ (n : Nat), ¬a = 23 → ¬a = n → motive n → motive n.succ) (a✝ : Nat) : motive a✝
-/
#guard_msgs in
#check foo.induct

View file

@ -26,10 +26,8 @@ info: f.eq_2 (x_1 y : Nat) (zs : List Nat) (x_2 : zs = [] → False) : f (x_1 ::
#check f.eq_2
/--
info: f.eq_3 :
∀ (x : List Nat),
(∀ (x_1 y : Nat), x = [x_1, y] → False) →
(∀ (x_1 y : Nat) (zs : List Nat), x = x_1 :: y :: zs → False) → f x = ([], [])
info: f.eq_3 (x✝ : List Nat) (x_2 : ∀ (x y : Nat), x✝ = [x, y] → False)
(x_3 : ∀ (x y : Nat) (zs : List Nat), x✝ = x :: y :: zs → False) : f x✝ = ([], [])
-/
#guard_msgs in
#check f.eq_3

View file

@ -40,12 +40,11 @@ def nonrecfun : Bool → Nat
| true => 0
/--
info: nonrecfun.eq_def :
∀ (x : Bool),
nonrecfun x =
match x with
| false => 0
| true => 0
info: nonrecfun.eq_def (x✝ : Bool) :
nonrecfun x✝ =
match x✝ with
| false => 0
| true => 0
-/
#guard_msgs in
#check nonrecfun.eq_def
@ -63,12 +62,11 @@ def fact : Nat → Nat
| n+1 => (n+1) * fact n
/--
info: fact.eq_def :
∀ (x : Nat),
fact x =
match x with
| 0 => 1
| n.succ => (n + 1) * fact n
info: fact.eq_def (x✝ : Nat) :
fact x✝ =
match x✝ with
| 0 => 1
| n.succ => (n + 1) * fact n
-/
#guard_msgs in
#check fact.eq_def

View file

@ -631,7 +631,7 @@ namespace FunIndTests
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
(case6 : motive_2 B.empty) (a✝ : A) : motive_1 a✝
-/
#guard_msgs in
#check A.size.induct
@ -649,7 +649,7 @@ info: A.subs.induct (motive_1 : A → Prop) (motive_2 : B → Prop) (case1 : ∀
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
(case3 : motive MutualIndNonMutualFun.A.empty) (a✝ : MutualIndNonMutualFun.A) : motive a✝
-/
#guard_msgs in
#check MutualIndNonMutualFun.A.self_size.induct
@ -658,8 +658,8 @@ info: MutualIndNonMutualFun.A.self_size.induct (motive : MutualIndNonMutualFun.A
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_1 : MutualIndNonMutualFun.A), motive a a_1
(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
@ -668,7 +668,7 @@ info: MutualIndNonMutualFun.A.self_size_with_param.induct (motive : Nat → Mutu
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
(case6 : motive_2 B.empty) (a✝ : A) : motive_1 a✝
-/
#guard_msgs in
#check A.hasNoBEmpty.induct
@ -676,7 +676,7 @@ info: A.hasNoBEmpty.induct (motive_1 : A → Prop) (motive_2 : B → Prop) (case
/--
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
(case4 : ∀ (n : Nat), motive_1 n → motive_2 n.succ) (a✝ : Nat) : motive_1 a✝
-/
#guard_msgs in
#check EvenOdd.isEven.induct

View file

@ -12,12 +12,11 @@ theorem Option_map.eq_2.{u_1, u_2} : ∀ {α : Type u_1} {β : Type u_2} (f : α
#print equations Option_map
/--
info: Option_map.eq_def.{u_1, u_2} {α : Type u_1} {β : Type u_2} (f : α → β) :
∀ (x : Option α),
Option_map f x =
match x with
| none => none
| some x => some (f x)
info: Option_map.eq_def.{u_1, u_2} {α : Type u_1} {β : Type u_2} (f : α → β) (x✝ : Option α) :
Option_map f x✝ =
match x✝ with
| none => none
| some x => some (f x)
-/
#guard_msgs in
#check Option_map.eq_def

View file

@ -14,15 +14,14 @@ theorem foo.eq_3 : ∀ (x n : Nat), foo n.succ x = foo n x
#print equations foo
/--
info: foo.eq_def :
∀ (x x_1 : Nat),
foo x x_1 =
match x, x_1 with
| 0, m =>
match m with
| 0 => 0
| m => m
| n.succ, m => foo n m
info: foo.eq_def (x✝ x✝¹ : Nat) :
foo x✝ x✝¹ =
match x✝, x✝¹ with
| 0, m =>
match m with
| 0 => 0
| m => m
| n.succ, m => foo n m
-/
#guard_msgs in
#check foo.eq_def
@ -51,15 +50,14 @@ theorem bar.eq_2 : ∀ (x n : Nat), bar n.succ x = bar n x
#print equations bar
/--
info: bar.eq_def :
∀ (x x_1 : Nat),
bar x x_1 =
match x, x_1 with
| 0, m =>
match m with
| 0 => 0
| m => m
| n.succ, m => bar n m
info: bar.eq_def (x✝ x✝¹ : Nat) :
bar x✝ x✝¹ =
match x✝, x✝¹ with
| 0, m =>
match m with
| 0 => 0
| m => m
| n.succ, m => bar n m
-/
#guard_msgs in
#check bar.eq_def
@ -83,15 +81,14 @@ theorem Structural.foo.eq_3 : ∀ (x n : Nat), foo n.succ x = foo n x
#print equations foo
/--
info: Structural.foo.eq_def :
∀ (x x_1 : Nat),
foo x x_1 =
match x, x_1 with
| 0, m =>
match m with
| 0 => 0
| m => m
| n.succ, m => foo n m
info: Structural.foo.eq_def (x✝ x✝¹ : Nat) :
foo x✝ x✝¹ =
match x✝, x✝¹ with
| 0, m =>
match m with
| 0 => 0
| m => m
| n.succ, m => foo n m
-/
#guard_msgs in
#check foo.eq_def
@ -120,15 +117,14 @@ theorem Structural.bar.eq_2 : ∀ (x n : Nat), bar n.succ x = bar n x
#print equations bar
/--
info: Structural.bar.eq_def :
∀ (x x_1 : Nat),
bar x x_1 =
match x, x_1 with
| 0, m =>
match m with
| 0 => 0
| m => m
| n.succ, m => bar n m
info: Structural.bar.eq_def (x✝ x✝¹ : Nat) :
bar x✝ x✝¹ =
match x✝, x✝¹ with
| 0, m =>
match m with
| 0 => 0
| m => m
| n.succ, m => bar n m
-/
#guard_msgs in
#check bar.eq_def