internally rename lemma to theorem #108
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user