internally rename lemma to theorem #108

pull/251/merge
Jon Eugster 9 months ago
parent 17d2ba5a2c
commit 1f14ad185f

@ -76,7 +76,7 @@ function DualEditorMain({ worldId, levelId, level, worldSize }: { worldId: strin
// On completion, add the names of all new items to the local storage
let newTiles = [
...level?.tactics,
...level?.lemmas,
...level?.theorems,
...level?.definitions
].filter((tile) => tile.new).map((tile) => tile.name)

@ -48,7 +48,7 @@ function InventoryItem({item, name, displayName, locked, disabled, newly, showDo
const icon = locked ? <FontAwesomeIcon icon={faLock} /> :
disabled ? <FontAwesomeIcon icon={faBan} /> : <></>
const className = locked ? "locked" : disabled ? "disabled" : newly ? "new" : ""
// Note: This is somewhat a hack as the statement of lemmas comes currently in the form
// Note: This is somewhat a hack as the statement of theorems comes currently in the form
// `Namespace.statement_name (x y : Nat) : some type`
const title = locked ? t("Not unlocked yet") :
disabled ? t("Not available in this level") : (item.altTitle ? item.altTitle.substring(item.altTitle.indexOf(' ') + 1) : '')
@ -172,12 +172,12 @@ export function Inventory () {
<div className="inventory">
{ levelInfo.data ? <>
<div className="tab-bar major">
<div className={`tab${(categoryTab == "theorem") ? " active": ""}${containsNew(levelInfo.data?.lemmas) ? " new" : ""}`} onClick={() => { setCategoryTab("theorem") }}>{t("Theorems")}</div>
<div className={`tab${(categoryTab == "theorem") ? " active": ""}${containsNew(levelInfo.data?.theorems) ? " new" : ""}`} onClick={() => { setCategoryTab("theorem") }}>{t("Theorems")}</div>
<div className={`tab${(categoryTab == "tactic") ? " active": ""}${containsNew(levelInfo.data?.tactics) ? " new" : ""}`} onClick={() => { setCategoryTab("tactic") }}>{t("Tactics")}</div>
<div className={`tab${(categoryTab == "definition") ? " active": ""}${containsNew(levelInfo.data?.definitions) ? " new" : ""}`} onClick={() => { setCategoryTab("definition") }}>{t("Definitions")}</div>
</div>
{ (categoryTab == "theorem") &&
<InventoryList items={levelInfo.data?.lemmas} tab={theoremTab} setTab={setTheoremTab} />
<InventoryList items={levelInfo.data?.theorems} tab={theoremTab} setTab={setTheoremTab} />
}
{ (categoryTab == "tactic") &&
<InventoryList items={levelInfo.data?.tactics} />
@ -228,7 +228,7 @@ export function Documentation() {
</div>
}
/** The panel showing the user's inventory with tactics, definitions, and lemmas */
/** The panel showing the user's inventory with tactics, definitions, and theorems */
export function InventoryPanel({visible = true}) {
const {gameId, worldId, levelId} = React.useContext(GameIdContext)
const levelInfo = useLoadLevelQuery({game: gameId, world: worldId, level: levelId})
@ -240,10 +240,10 @@ export function InventoryPanel({visible = true}) {
const [docTile, setDocTile] = useState<InventoryTile>(null)
useEffect(() => {
// If the level specifies `LemmaTab "Nat"`, we switch to this tab on loading.
// If the level specifies `TheoremTab "Nat"`, we switch to this tab on loading.
// `defaultTab` is `null` or `undefined` otherwise, in which case we don't want to switch.
if (levelInfo?.data?.lemmaTab) {
setTheoremTab(levelInfo?.data?.lemmaTab)
if (levelInfo?.data?.theoremTab) {
setTheoremTab(levelInfo?.data?.theoremTab)
}}, [levelInfo])
return <div className={`column inventory-panel ${visible ? '' : 'hidden'}`}>

@ -47,11 +47,11 @@ export interface LevelInfo {
conclusion: null|string,
index: number,
tactics: InventoryTile[],
lemmas: InventoryTile[],
theorems: InventoryTile[],
definitions: InventoryTile[],
descrText: null|string,
descrFormat: null|string,
lemmaTab: null|string,
theoremTab: null|string,
statementName: null|string,
displayName: null|string,
template: null|string,
@ -61,9 +61,9 @@ export interface LevelInfo {
/** Used to display the inventory on the welcome page */
export interface InventoryOverview {
tactics: InventoryTile[],
lemmas: InventoryTile[],
theorems: InventoryTile[],
definitions: InventoryTile[],
lemmaTab: null,
theoremTab: null,
}
interface Doc {

@ -48,9 +48,9 @@ only evaluated at the beginning of the proof.
## Attributes
You can add attributes as you would for a `theorem`. Most notably, you can make your named exercise a `simp` lemma:
You can add attributes as you would for a `theorem`. Most notably, you can make your named exercise a `simp` theorem:
```lean
@[simp]
Statement my_simp_lemma ...
Statement my_simp_theorem ...
```

@ -176,7 +176,7 @@ elab doc:docComment ? "TheoremDoc" name:ident "as" displayName:str "in" category
let doc ← parseDocCommentLegacy doc content
let doc ← doc.translate
modifyEnv (inventoryTemplateExt.addEntry · {
type := .Lemma
type := .Theorem
name := name.getId
category := category.getString
displayName := displayName.getString
@ -236,13 +236,13 @@ elab "NewHiddenTactic" args:ident* : command => do
/-- Declare theorems that are introduced by this level. -/
elab "NewTheorem" args:ident* : command => do
checkCommandNotDuplicated ((←getCurLevel).lemmas.new) "NewTheorem"
checkCommandNotDuplicated ((←getCurLevel).theorems.new) "NewTheorem"
for name in ↑args do
try let _decl ← getConstInfo name.getId catch
| _ => logErrorAt name m!"unknown identifier '{name}'."
checkInventoryDoc .Lemma name -- TODO: Add (template := "[mathlib]")
checkInventoryDoc .Theorem name -- TODO: Add (template := "[mathlib]")
modifyCurLevel fun level => pure {level with
lemmas := {level.lemmas with new := args.map (·.getId)}}
theorems := {level.theorems with new := args.map (·.getId)}}
/-- Declare definitions that are introduced by this level. -/
elab "NewDefinition" args:ident* : command => do
@ -262,10 +262,10 @@ elab "DisabledTactic" args:ident* : command => do
/-- Declare theorems that are temporarily disabled in this level.
This is ignored if `OnlyTheorem` is set. -/
elab "DisabledTheorem" args:ident* : command => do
checkCommandNotDuplicated ((←getCurLevel).lemmas.disabled) "DisabledTheorem"
for name in ↑args do checkInventoryDoc .Lemma name
checkCommandNotDuplicated ((←getCurLevel).theorems.disabled) "DisabledTheorem"
for name in ↑args do checkInventoryDoc .Theorem name
modifyCurLevel fun level => pure {level with
lemmas := {level.lemmas with disabled := args.map (·.getId)}}
theorems := {level.theorems with disabled := args.map (·.getId)}}
/-- Declare definitions that are temporarily disabled in this level -/
elab "DisabledDefinition" args:ident* : command => do
@ -283,10 +283,10 @@ elab "OnlyTactic" args:ident* : command => do
/-- Temporarily disable all theorems except the ones declared here -/
elab "OnlyTheorem" args:ident* : command => do
checkCommandNotDuplicated ((←getCurLevel).lemmas.only) "OnlyTheorem"
for name in ↑args do checkInventoryDoc .Lemma name
checkCommandNotDuplicated ((←getCurLevel).theorems.only) "OnlyTheorem"
for name in ↑args do checkInventoryDoc .Theorem name
modifyCurLevel fun level => pure {level with
lemmas := {level.lemmas with only := args.map (·.getId)}}
theorems := {level.theorems with only := args.map (·.getId)}}
/-- Temporarily disable all definitions except the ones declared here.
This is ignored if `OnlyDefinition` is set. -/
@ -296,10 +296,10 @@ elab "OnlyDefinition" args:ident* : command => do
modifyCurLevel fun level => pure {level with
definitions := {level.definitions with only := args.map (·.getId)}}
/-- Define which tab of Lemmas is opened by default. Usage: `TheoremTab "Nat"`.
/-- Define which tab of Theorems is opened by default. Usage: `TheoremTab "Nat"`.
If omitted, the current tab will remain open. -/
elab "TheoremTab" category:str : command =>
modifyCurLevel fun level => pure {level with lemmaTab := category.getString}
modifyCurLevel fun level => pure {level with theoremTab := category.getString}
/-! DEPRECATED -/
@ -309,7 +309,7 @@ elab doc:docComment ? "LemmaDoc" name:ident "as" displayName:str "in" category:s
logWarning "Deprecated. Has been renamed to `TheoremDoc`"
let doc ← parseDocCommentLegacy doc content
modifyEnv (inventoryTemplateExt.addEntry · {
type := .Lemma
type := .Theorem
name := name.getId
category := category.getString
displayName := displayName.getString
@ -317,31 +317,31 @@ elab doc:docComment ? "LemmaDoc" name:ident "as" displayName:str "in" category:s
elab "NewLemma" args:ident* : command => do
logWarning "Deprecated. Has been renamed to `NewTheorem`"
checkCommandNotDuplicated ((←getCurLevel).lemmas.new) "NewLemma"
checkCommandNotDuplicated ((←getCurLevel).theorems.new) "NewTheorem"
for name in ↑args do
try let _decl ← getConstInfo name.getId catch
| _ => logErrorAt name m!"unknown identifier '{name}'."
checkInventoryDoc .Lemma name -- TODO: Add (template := "[mathlib]")
checkInventoryDoc .Theorem name -- TODO: Add (template := "[mathlib]")
modifyCurLevel fun level => pure {level with
lemmas := {level.lemmas with new := args.map (·.getId)}}
theorems := {level.theorems with new := args.map (·.getId)}}
elab "DisabledLemma" args:ident* : command => do
logWarning "Deprecated. Has been renamed to `DisabledTheorem`"
checkCommandNotDuplicated ((←getCurLevel).lemmas.disabled) "DisabledLemma"
for name in ↑args do checkInventoryDoc .Lemma name
checkCommandNotDuplicated ((←getCurLevel).theorems.disabled) "DisabledTheorem"
for name in ↑args do checkInventoryDoc .Theorem name
modifyCurLevel fun level => pure {level with
lemmas := {level.lemmas with disabled := args.map (·.getId)}}
theorems := {level.theorems with disabled := args.map (·.getId)}}
elab "OnlyLemma" args:ident* : command => do
logWarning "Deprecated. Has been renamed to `OnlyTheorem`"
checkCommandNotDuplicated ((←getCurLevel).lemmas.only) "OnlyLemma"
for name in ↑args do checkInventoryDoc .Lemma name
checkCommandNotDuplicated ((←getCurLevel).theorems.only) "OnlyTheorem"
for name in ↑args do checkInventoryDoc .Theorem name
modifyCurLevel fun level => pure {level with
lemmas := {level.lemmas with only := args.map (·.getId)}}
theorems := {level.theorems with only := args.map (·.getId)}}
elab "LemmaTab" category:str : command => do
logWarning "Deprecated. Has been renamed to `TheoremTab`"
modifyCurLevel fun level => pure {level with lemmaTab := category.getString}
modifyCurLevel fun level => pure {level with theoremTab := category.getString}
/-! # Exercise Statement -/
@ -388,7 +388,7 @@ elab doc:docComment ? attrs:Parser.Term.attributes ?
let defaultDeclName : Ident := mkIdent <| (← getCurGame).name ++ (← getCurWorld).name ++
("level" ++ toString lvlIdx : String)
-- Collect all used tactics/lemmas in the sample proof:
-- Collect all used tactics/theorems in the sample proof:
let usedInventory : UsedInventory ← match val with
| `(Parser.Command.declVal| := $proof:term) => do
collectUsedInventory proof
@ -417,12 +417,12 @@ elab doc:docComment ? attrs:Parser.Term.attributes ?
let thmStatement ← `(command| $[$doc]? $[$attrs:attributes]? theorem $defaultDeclName $sig := by {let_intros; $(⟨preambleSeq⟩); $(⟨tacticStx⟩)})
elabCommand thmStatement
-- Check that statement has a docs entry.
checkInventoryDoc .Lemma name (name := fullName) (template := docContent)
checkInventoryDoc .Theorem name (name := fullName) (template := docContent)
else
let thmStatement ← `(command| $[$doc]? $[$attrs:attributes]? theorem $name $sig := by {let_intros; $(⟨preambleSeq⟩); $(⟨tacticStx⟩)})
elabCommand thmStatement
-- Check that statement has a docs entry.
checkInventoryDoc .Lemma name (name := fullName) (template := docContent)
checkInventoryDoc .Theorem name (name := fullName) (template := docContent)
| none =>
let thmStatement ← `(command| $[$doc]? $[$attrs:attributes]? theorem $defaultDeclName $sig := by {let_intros; $(⟨preambleSeq⟩); $(⟨tacticStx⟩)})
elabCommand thmStatement
@ -511,7 +511,7 @@ elab doc:docComment ? attrs:Parser.Term.attributes ?
hints := hints
tactics := {level.tactics with used := usedInventory.tactics.toArray}
definitions := {level.definitions with used := usedInventory.definitions.toArray}
lemmas := {level.lemmas with used := usedInventory.lemmas.toArray}
theorems := {level.theorems with used := usedInventory.theorems.toArray}
}
/-! # Hints -/
@ -644,7 +644,7 @@ elab "Template" tacs:tacticSeq : tactic => do
-- open Lean Meta Elab Command Tactic Simp
-- def Lean.Meta.SimpTheorems.hasAttribute (d : SimpTheorems) (decl : Name) :=
-- d.isLemma (.decl decl) || d.isDeclToUnfold decl
-- d.isTheorem (.decl decl) || d.isDeclToUnfold decl
-- def isInSimpset (simpAttr decl: Name) : CoreM Bool := do
-- let .some simpDecl ←getSimpExtension? simpAttr | return false
@ -662,8 +662,8 @@ def Parser.dependency := Parser.sepBy1Indent Parser.ident "→"
/-- Manually add a dependency between two worlds.
Normally, the dependencies are computed automatically by the
tactics & lemmas used in the example
proof and the ones introduced by `NewLemma`/`NewTactic`.
tactics & theorems used in the example
proof and the ones introduced by `NewTheorem`/`NewTactic`.
Use the command `Dependency World₁ → World₂` to add a manual edge to the graph,
for example if the only dependency between the worlds is given by
the narrative. -/
@ -708,10 +708,10 @@ elab "MakeGame" : command => do
s!"[mathlib doc](https://leanprover-community.github.io/mathlib4_docs/find/?pattern={name}#doc)"
match item.type with
| .Lemma =>
| .Theorem =>
modifyEnv (inventoryExt.addEntry · { item with
content := content
-- Add the lemma statement to the doc
-- Add the theorem statement to the doc
statement := (← getStatementString name)
})
| _ =>
@ -736,14 +736,14 @@ elab "MakeGame" : command => do
for (worldId, world) in allWorlds do
let mut usedItems : HashSet Name := {}
let mut newItems : HashSet Name := {}
for inventoryType in #[.Tactic, .Definition, .Lemma] do
for inventoryType in #[.Tactic, .Definition, .Theorem] do
for (levelId, level) in world.levels.toArray do
usedItems := usedItems.insertMany (level.getInventory inventoryType).used
newItems := newItems.insertMany (level.getInventory inventoryType).new
hiddenItems := hiddenItems.insertMany (level.getInventory inventoryType).hidden
-- if the previous level was named, we need to add it as a new lemma
if inventoryType == .Lemma then
-- if the previous level was named, we need to add it as a new theorem
if inventoryType == .Theorem then
match levelId with
| 0 => pure ()
| 1 => pure () -- level ids start with 1, so we need to skip 1, too
@ -756,9 +756,9 @@ elab "MakeGame" : command => do
let name := Name.str pre s
newItems := newItems.insert name
if inventoryType == .Lemma then
if inventoryType == .Theorem then
-- if the last level was named, we need to add it as a new lemma
-- if the last level was named, we need to add it as a new theorem
let i₀ := world.levels.size
let some idx := world.levels.find? (i₀) | throwError s!"Level {i₀} not found for world {worldId}!"
@ -863,27 +863,27 @@ elab "MakeGame" : command => do
let mut allItemsByType : HashMap InventoryType (HashSet Name) := {}
-- Compute which inventory items are available in which level:
for inventoryType in #[.Tactic, .Definition, .Lemma] do
for inventoryType in #[.Tactic, .Definition, .Theorem] do
-- Which items are introduced in which world?
let mut lemmaStatements : HashMap (Name × Nat) Name := {}
let mut theoremStatements : HashMap (Name × Nat) Name := {}
-- TODO: I believe `newItemsInWorld` has way to many elements in it which we iterate over
-- e.g. we iterate over `ring` for `Lemma`s as well, but so far that seems to cause no problems
-- e.g. we iterate over `ring` for `Theorem`s as well, but so far that seems to cause no problems
let mut allItems : HashSet Name := {}
for (worldId, world) in game.worlds.nodes.toArray do
let mut newItems : HashSet Name := {}
for (levelId, level) in world.levels.toArray do
let newLemmas := (level.getInventory inventoryType).new
newItems := newItems.insertMany newLemmas
allItems := allItems.insertMany newLemmas
if inventoryType == .Lemma then
let newTheorems := (level.getInventory inventoryType).new
newItems := newItems.insertMany newTheorems
allItems := allItems.insertMany newTheorems
if inventoryType == .Theorem then
-- For levels `2, 3, …` we check if the previous level was named
-- in which case we add it as available lemma.
-- in which case we add it as available theorem.
match levelId with
| 0 => pure ()
| 1 => pure () -- level ids start with 1, so we need to skip 1, too.
| i₀ + 1 =>
-- add named statement from previous level to the available lemmas.
-- add named statement from previous level to the available theorems.
let some idx := world.levels.find? (i₀) | throwError s!"Level {i₀ + 1} not found for world {worldId}!"
match (idx).statementName with
| .anonymous => pure ()
@ -892,9 +892,9 @@ elab "MakeGame" : command => do
let name := Name.str pre s
newItems := newItems.insert name
allItems := allItems.insert name
lemmaStatements := lemmaStatements.insert (worldId, levelId) name
if inventoryType == .Lemma then
-- if named, add the lemma from the last level of the world to the inventory
theoremStatements := theoremStatements.insert (worldId, levelId) name
if inventoryType == .Theorem then
-- if named, add the theorem from the last level of the world to the inventory
let i₀ := world.levels.size
match i₀ with
| 0 => logWarning m!"World `{worldId}` contains no levels."
@ -916,7 +916,7 @@ elab "MakeGame" : command => do
-- Using a match statement because the error message of `Option.get!` is not helpful.
match (← getInventoryItem? item inventoryType) with
| none =>
-- Note: we did have a panic here before because lemma statement and doc entry
-- Note: we did have a panic here before because theorem statement and doc entry
-- had mismatching namespaces
logError m!"There is no inventory item ({inventoryType}) for: {item}."
panic s!"Inventory item {item} not found!"
@ -970,8 +970,8 @@ elab "MakeGame" : command => do
-- add the exercise statement from the previous level
-- if it was named
if inventoryType == .Lemma then
match lemmaStatements.find? (worldId, levelId) with
if inventoryType == .Theorem then
match theoremStatements.find? (worldId, levelId) with
| none => pure ()
| some name =>
let data := (← getInventoryItem? name inventoryType).get!
@ -986,7 +986,7 @@ elab "MakeGame" : command => do
altTitle := data.statement
locked := false }
-- add marks for `disabled` and `new` lemmas here, so that they only apply to
-- add marks for `disabled` and `new` theorems here, so that they only apply to
-- the current level.
let itemsArray := items.toArray
|>.insertionSort (fun a b => a.1.toString < b.1.toString)
@ -1009,10 +1009,10 @@ elab "MakeGame" : command => do
| throwError "Expected item to exist: {name}"
return item.toTile)
let inventory : InventoryOverview := {
lemmas := (← getTiles .Lemma).map (fun tile => {tile with hidden := hiddenItems.contains tile.name})
theorems := (← getTiles .Theorem).map (fun tile => {tile with hidden := hiddenItems.contains tile.name})
tactics := (← getTiles .Tactic).map (fun tile => {tile with hidden := hiddenItems.contains tile.name})
definitions := (← getTiles .Definition).map (fun tile => {tile with hidden := hiddenItems.contains tile.name})
lemmaTab := none
theoremTab := none
}
saveGameData allItemsByType inventory

@ -32,40 +32,40 @@ open Lean
/-! ## Inventory (documentation)
The inventory contains documentation that the user can access.
There are three inventory types: Lemma, Tactic, Definition. They vary about in the information
There are three inventory types: Theorem, Tactic, Definition. They vary about in the information
they carry.
The commands `TheoremDoc`, `TacticDoc`, and `DefinitionDoc` add keys and templates to an
env. extension called `InventoryTemplateExt`. Commands like `NewLemma`, etc. as well as
env. extension called `InventoryTemplateExt`. Commands like `NewTheorem`, etc. as well as
`Statement` check if there is a key registered in this extension and might add a default or
print a warning if not.
Then, `MakeGame` takes the templates from `InventoryTemplateExt` and creates the documentation entries
that are sent to the client. This allows us to modify them like adding information from
mathlib or from parsing the lemma in question.
mathlib or from parsing the theorem in question.
-/
/-- The game knows three different inventory types that contain slightly different information -/
inductive InventoryType := | Tactic | Lemma | Definition
inductive InventoryType := | Tactic | Theorem | Definition
deriving ToJson, FromJson, Repr, BEq, Hashable, Inhabited
-- TODO: golf this?
instance : ToString InventoryType := ⟨fun t => match t with
| .Tactic => "Tactic"
| .Lemma => "Lemma"
| .Theorem => "Theorem"
| .Definition => "Definition"⟩
/-- The keys/templates of the inventory items, stored in `InventoryTemplateExt`. -/
structure InventoryTemplate where
/-- Lemma, Tactic, or Definition -/
/-- Theorem, Tactic, or Definition -/
type: InventoryType
/-- Depends on the type:
* Tactic: the tactic's name
* Lemma: fully qualified lemma name
* Theorem: fully qualified theorem name
* Definition: no restrictions (preferably the definitions fully qualified name)
-/
name: Name
/-- Only for Lemmas. To sort them into tabs -/
/-- Only for Theorems. To sort them into tabs -/
category: String := default
/-- Free-text short name -/
displayName: String := name.toString
@ -85,13 +85,13 @@ structure InventoryTile where
The name of the item. The restrictions are:
* for Tactics: The name of the tactic.
* for Lemmas: *Fully qualified* lemma name.
* for Theorems: *Fully qualified* theorem name.
* for Definitions: no restrictions.
-/
name : Name
/-- The display name shown in the inventory. This can be free-text. -/
displayName : String
/-- Category to group inventory items by (currently only used for lemmas). -/
/-- Category to group inventory items by (currently only used for theorems). -/
category : String
/-- The world which introduced this item. -/
world : Option Name := none
@ -146,16 +146,16 @@ def getInventoryItem? [Monad m] [MonadEnv m] (n : Name) (type : InventoryType) :
structure InventoryOverview where
tactics : Array InventoryTile
lemmas : Array InventoryTile
theorems : Array InventoryTile
definitions : Array InventoryTile
lemmaTab : Option String
theoremTab : Option String
deriving ToJson, FromJson
-- TODO: Reuse the following code for checking available tactics in user code:
structure UsedInventory where
(tactics : HashSet Name := {})
(definitions : HashSet Name := {})
(lemmas : HashSet Name := {})
(theorems : HashSet Name := {})
/-! ## Environment extensions for game specification -/
@ -255,7 +255,7 @@ structure GameLevel where
/-- Introduction text shown all the time. (markdown) -/
introduction: String := default
conclusion: String := default
/-- The name of the exercise proven. If provided this lemma will be available in
/-- The name of the exercise proven. If provided this theorem will be available in
future levels. -/
statementName: Name := default
hints: Array GoalHintEntry := default
@ -265,13 +265,13 @@ structure GameLevel where
/-- The mathematical statement in mathematician-readable form. (markdown) -/
descrText: Option String := none
descrFormat : String := default
/-- The `category` of lemmas to be open by default -/
lemmaTab: Option String := none
/-- The `category` of theorems to be open by default -/
theoremTab: Option String := none
/-- The module to be imported when playing this level -/
module : Name := default
tactics: InventoryInfo := default
definitions: InventoryInfo := default
lemmas: InventoryInfo := default
theorems: InventoryInfo := default
/-- A proof template that is printed in an empty editor. -/
template: Option String := none
/-- The image for this level. -/
@ -282,20 +282,20 @@ deriving Inhabited, Repr
/-- Json-encodable version of `GameLevel`
Fields:
- description: Lemma in mathematical language.
- descriptionGoal: Lemma printed as Lean-Code.
- description: Theorem in mathematical language.
- descriptionGoal: Theorem printed as Lean-Code.
-/
structure LevelInfo where
index : Nat
title : String
tactics : Array InventoryTile
lemmas : Array InventoryTile
theorems : Array InventoryTile
definitions : Array InventoryTile
introduction : String
conclusion : String
descrText : Option String := none
descrFormat : String := ""
lemmaTab : Option String
theoremTab : Option String
module : Name
displayName : Option String
statementName : Option String
@ -307,17 +307,17 @@ def GameLevel.toInfo (lvl : GameLevel) (env : Environment) : LevelInfo :=
{ index := lvl.index,
title := lvl.title,
tactics := lvl.tactics.tiles,
lemmas := lvl.lemmas.tiles,
theorems := lvl.theorems.tiles,
definitions := lvl.definitions.tiles,
descrText := lvl.descrText,
descrFormat := lvl.descrFormat --toExpr <| format (lvl.goal.raw) --toString <| Syntax.formatStx (lvl.goal.raw) --Syntax.formatStx (lvl.goal.raw) , -- TODO
introduction := lvl.introduction
conclusion := lvl.conclusion
lemmaTab := match lvl.lemmaTab with
theoremTab := match lvl.theoremTab with
| some tab => tab
| none =>
-- Try to set the lemma tab to the category of the first added lemma
match lvl.lemmas.tiles.find? (·.new) with
-- Try to set the theorem tab to the category of the first added theorem
match lvl.theorems.tiles.find? (·.new) with
| some tile => tile.category
| none => none
statementName := lvl.statementName.toString
@ -325,11 +325,11 @@ def GameLevel.toInfo (lvl : GameLevel) (env : Environment) : LevelInfo :=
displayName := match lvl.statementName with
| .anonymous => none
| name => match (inventoryExt.getState env).find?
(fun x => x.name == name && x.type == .Lemma) with
(fun x => x.name == name && x.type == .Theorem) with
| some n => n.displayName
| none => name.toString
-- Note: we could call `.find!` because we check in `Statement` that the
-- lemma doc must exist.
-- theorem doc must exist.
template := lvl.template
image := lvl.image
}
@ -536,7 +536,7 @@ def modifyLevel (levelId : LevelId) (fn : GameLevel → m GameLevel) [MonadError
-- def getIntroducedInventory (game : Game) [MonadError m] : m (Array Name) := do
-- let allItems : Array Name := game.worlds.nodes.fold (fun L _ world => L ++
-- world.levels.fold (fun LL _ level =>
-- LL ++ level.tactics.new ++ level.lemmas.new
-- LL ++ level.tactics.new ++ level.theorems.new
-- ) #[]) #[]
-- pure allItems

@ -166,7 +166,7 @@ partial def findForbiddenTactics (inputCtx : Parser.InputContext) (workerState :
-- Forbid the theorem we are proving currently
addMessage info inputCtx (severity := .error)
s!"Structural recursion: you can't use '{n}' to proof itself!"
let theoremsAndDefs := levelInfo.lemmas ++ levelInfo.definitions
let theoremsAndDefs := levelInfo.theorems ++ levelInfo.definitions
match theoremsAndDefs.find? (·.name == n) with
| none =>
-- Theorem will never be introduced in this game

@ -81,7 +81,7 @@ def getStatement (name : Name) : CommandElabM MessageData := do
-- Note: We use `String` because we can't send `MessageData` as json, but
-- `MessageData` might be better for interactive highlighting.
/-- Get a string of the form `my_lemma (n : ) : n + n = 2 * n`.
/-- Get a string of the form `my_theorem (n : ) : n + n = 2 * n`.
Note: A statement like `theorem abc : ∀ x : Nat, x ≥ 0` would be turned into
`theorem abc (x : Nat) : x ≥ 0` by `PrettyPrinter.ppSignature`. -/

@ -59,7 +59,7 @@ def getDocstring (env : Environment) (name : Name) (type : InventoryType) :
match type with
-- for tactics it's a lookup following mathlib's `#help`. not guaranteed to be the correct one.
| .Tactic => getTacticDocstring env name
| .Lemma => findDocString? env name
| .Theorem => findDocString? env name
-- TODO: for definitions not implemented yet, does it work?
| .Definition => findDocString? env name
@ -99,14 +99,14 @@ def checkInventoryDoc (type : InventoryType) (ref : Ident) (name : Name := ref.g
modifyEnv (inventoryTemplateExt.addEntry · {
type := type
name := name
category := if type == .Lemma then s!"{n.getPrefix}" else ""
category := if type == .Theorem then s!"{n.getPrefix}" else ""
content := docstring})
-- Add the default documentation
| some s =>
modifyEnv (inventoryTemplateExt.addEntry · {
type := type
name := name
category := if type == .Lemma then s!"{n.getPrefix}" else ""
category := if type == .Theorem then s!"{n.getPrefix}" else ""
content := s })
logInfoAt ref (m!"Missing {type} Documentation: {name}, used default (e.g. provided " ++
m!"docstring) instead. If you want to write a different description, add " ++
@ -133,7 +133,7 @@ partial def collectUsedInventory (stx : Syntax) (acc : UsedInventory := {}) : Co
catch | _ => pure [] -- catch "unknown constant" error
return ← ns.foldlM (fun acc n => do
if let some (.thmInfo ..) := (← getEnv).find? n then
return {acc with lemmas := acc.lemmas.insertMany ns}
return {acc with theorems := acc.theorems.insertMany ns}
else
return {acc with definitions := acc.definitions.insertMany ns}
) acc
@ -143,10 +143,10 @@ partial def collectUsedInventory (stx : Syntax) (acc : UsedInventory := {}) : Co
def GameLevel.getInventory (level : GameLevel) : InventoryType → InventoryInfo
| .Tactic => level.tactics
| .Definition => level.definitions
| .Lemma => level.lemmas
| .Theorem => level.theorems
def GameLevel.setComputedInventory (level : GameLevel) :
InventoryType → Array InventoryTile → GameLevel
| .Tactic, v => {level with tactics := {level.tactics with tiles := v}}
| .Definition, v => {level with definitions := {level.definitions with tiles := v}}
| .Lemma, v => {level with lemmas := {level.lemmas with tiles := v}}
| .Theorem, v => {level with theorems := {level.theorems with tiles := v}}

@ -51,7 +51,7 @@ def saveGameData (allItemsByType : HashMap InventoryType (HashSet Name))
IO.FS.writeFile (path / gameFileName) (toString (getGameJson game))
for inventoryType in [InventoryType.Lemma, .Tactic, .Definition] do
for inventoryType in [InventoryType.Theorem, .Tactic, .Definition] do
for name in allItemsByType.findD inventoryType {} do
let some item ← getInventoryItem? name inventoryType
| throwError "Expected item to exist: {name}"

@ -53,9 +53,9 @@ def getTacticDocstring (name: Name) : CommandElabM String := do
-- TODO: Things we want:
-- 1) Getting docstring this way is a problem if we want to "reprove" a mathlib lemma because
-- 1) Getting docstring this way is a problem if we want to "reprove" a mathlib theorem because
-- either it would not be imported from mathlib or have a different name in `Statement`
-- 3) is the lemma a simp lemma? (are there other attributes on it? --> hard/impossible)
-- 3) is the theorem a simp theorem? (are there other attributes on it? --> hard/impossible)
-- 4) which mathlib file is it imported from?
-- 5) namespace
-- 6) tactics: are there alternative variations like `ext`, `ext?`, `ext1?`, …

@ -22,7 +22,7 @@ Statement foo.bar2 : 3 ≤ 7 := by
simp
NewLemma foo.bar
NewTheorem foo.bar
DisabledTactic tauto
@ -39,7 +39,7 @@ end myNamespace
/- Other tests -/
LemmaDoc add_zero as "add_zero" in "Nat" "(nothing)"
TheoremDoc add_zero as "add_zero" in "Nat" "(nothing)"
/-- test -/
Statement add_zero (n : Nat) : n + 0 = n := by
@ -58,7 +58,7 @@ Statement (n : Nat) : 0 + n = n := by
simp
NewLemma add_zero
NewTheorem add_zero
--attribute [simp] add_zero

Loading…
Cancel
Save