forked from leanprover/lean4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConstructions.lean
124 lines (112 loc) · 5.62 KB
/
Constructions.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.AuxRecursor
import Lean.Meta.AppBuilder
namespace Lean
@[extern "lean_mk_cases_on"] opaque mkCasesOnImp (env : Environment) (declName : @& Name) : Except KernelException Environment
@[extern "lean_mk_rec_on"] opaque mkRecOnImp (env : Environment) (declName : @& Name) : Except KernelException Environment
@[extern "lean_mk_no_confusion"] opaque mkNoConfusionCoreImp (env : Environment) (declName : @& Name) : Except KernelException Environment
@[extern "lean_mk_below"] opaque mkBelowImp (env : Environment) (declName : @& Name) : Except KernelException Environment
@[extern "lean_mk_ibelow"] opaque mkIBelowImp (env : Environment) (declName : @& Name) : Except KernelException Environment
@[extern "lean_mk_brec_on"] opaque mkBRecOnImp (env : Environment) (declName : @& Name) : Except KernelException Environment
@[extern "lean_mk_binduction_on"] opaque mkBInductionOnImp (env : Environment) (declName : @& Name) : Except KernelException Environment
variable [Monad m] [MonadEnv m] [MonadError m] [MonadOptions m]
@[inline] private def adaptFn (f : Environment → Name → Except KernelException Environment) (declName : Name) : m Unit := do
let env ← ofExceptKernelException (f (← getEnv) declName)
modifyEnv fun _ => env
def mkCasesOn (declName : Name) : m Unit := adaptFn mkCasesOnImp declName
def mkRecOn (declName : Name) : m Unit := adaptFn mkRecOnImp declName
def mkNoConfusionCore (declName : Name) : m Unit := adaptFn mkNoConfusionCoreImp declName
def mkBelow (declName : Name) : m Unit := adaptFn mkBelowImp declName
def mkIBelow (declName : Name) : m Unit := adaptFn mkIBelowImp declName
def mkBRecOn (declName : Name) : m Unit := adaptFn mkBRecOnImp declName
def mkBInductionOn (declName : Name) : m Unit := adaptFn mkBInductionOnImp declName
open Meta
def mkNoConfusionEnum (enumName : Name) : MetaM Unit := do
if (← getEnv).contains ``noConfusionEnum then
mkToCtorIdx
mkNoConfusionType
mkNoConfusion
else
-- `noConfusionEnum` was not defined yet, so we use `mkNoConfusionCore`
mkNoConfusionCore enumName
where
mkToCtorIdx : MetaM Unit := do
let ConstantInfo.inductInfo info ← getConstInfo enumName | unreachable!
let us := info.levelParams.map mkLevelParam
let numCtors := info.ctors.length
let declName := Name.mkStr enumName "toCtorIdx"
let enumType := mkConst enumName us
let natType := mkConst ``Nat
let declType ← mkArrow enumType natType
let mut minors := #[]
for i in [:numCtors] do
minors := minors.push <| mkNatLit i
withLocalDeclD `x enumType fun x => do
let motive ← mkLambdaFVars #[x] natType
let declValue ← mkLambdaFVars #[x] <| mkAppN (mkApp2 (mkConst (mkCasesOnName enumName) (levelOne::us)) motive x) minors
addAndCompile <| Declaration.defnDecl {
name := declName
levelParams := info.levelParams
type := declType
value := declValue
safety := DefinitionSafety.safe
hints := ReducibilityHints.abbrev
}
setReducibleAttribute declName
mkNoConfusionType : MetaM Unit := do
let ConstantInfo.inductInfo info ← getConstInfo enumName | unreachable!
let us := info.levelParams.map mkLevelParam
let v ← mkFreshUserName `v
let enumType := mkConst enumName us
let sortV := mkSort (mkLevelParam v)
let toCtorIdx := mkConst (Name.mkStr enumName "toCtorIdx") us
withLocalDeclD `P sortV fun P =>
withLocalDeclD `x enumType fun x =>
withLocalDeclD `y enumType fun y => do
let declType ← mkForallFVars #[P, x, y] sortV
let declValue ← mkLambdaFVars #[P, x, y] (← mkAppM ``noConfusionTypeEnum #[toCtorIdx, P, x, y])
let declName := Name.mkStr enumName "noConfusionType"
addAndCompile <| Declaration.defnDecl {
name := declName
levelParams := v :: info.levelParams
type := declType
value := declValue
safety := DefinitionSafety.safe
hints := ReducibilityHints.abbrev
}
setReducibleAttribute declName
mkNoConfusion : MetaM Unit := do
let ConstantInfo.inductInfo info ← getConstInfo enumName | unreachable!
let us := info.levelParams.map mkLevelParam
let v ← mkFreshUserName `v
let enumType := mkConst enumName us
let sortV := mkSort (mkLevelParam v)
let toCtorIdx := mkConst (Name.mkStr enumName "toCtorIdx") us
let noConfusionType := mkConst (Name.mkStr enumName "noConfusionType") (mkLevelParam v :: us)
withLocalDecl `P BinderInfo.implicit sortV fun P =>
withLocalDecl `x BinderInfo.implicit enumType fun x =>
withLocalDecl `y BinderInfo.implicit enumType fun y => do
withLocalDeclD `h (← mkEq x y) fun h => do
let declType ← mkForallFVars #[P, x, y, h] (mkApp3 noConfusionType P x y)
let declValue ← mkLambdaFVars #[P, x, y, h] (← mkAppOptM ``noConfusionEnum #[none, none, none, toCtorIdx, P, x, y, h])
let declName := Name.mkStr enumName "noConfusion"
addAndCompile <| Declaration.defnDecl {
name := declName
levelParams := v :: info.levelParams
type := declType
value := declValue
safety := DefinitionSafety.safe
hints := ReducibilityHints.abbrev
}
setReducibleAttribute declName
modifyEnv fun env => markNoConfusion env declName
def mkNoConfusion (declName : Name) : MetaM Unit := do
if (← isEnumType declName) then
mkNoConfusionEnum declName
else
mkNoConfusionCore declName
end Lean