Skip to content

Commit fbfa10e

Browse files
committed
Merge remote-tracking branch 'upstream/master' into sorted_rename
2 parents 469ab94 + cc046e0 commit fbfa10e

File tree

1,591 files changed

+848309
-764565
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,591 files changed

+848309
-764565
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ jobs:
200200
"test": true,
201201
// NOTE: `test-speedcenter` currently seems to be broken on `ubuntu-latest`
202202
"test-speedcenter": large && level >= 2,
203-
// made explicit until it can be assumed to have propagated to PRs
204-
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
203+
// We are not warning-free yet on all platforms, start here
204+
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-Werror",
205205
},
206206
{
207207
"name": "Linux Reldebug",

.github/workflows/pr-release.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ jobs:
426426
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
427427
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
428428
git add lean-toolchain
429-
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
429+
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
430430
else
431431
echo "Branch already exists, updating lean-toolchain."
432432
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
@@ -435,7 +435,7 @@ jobs:
435435
git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories
436436
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
437437
git add lean-toolchain
438-
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
438+
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
439439
fi
440440
441441
- name: Push changes
@@ -496,7 +496,7 @@ jobs:
496496
sed -i 's,require "leanprover-community" / "batteries" @ git ".\+",require "leanprover-community" / "batteries" @ git "lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}",' lakefile.lean
497497
lake update batteries
498498
git add lakefile.lean lake-manifest.json
499-
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
499+
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
500500
else
501501
echo "Branch already exists, updating lean-toolchain and bumping Batteries."
502502
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
@@ -507,7 +507,7 @@ jobs:
507507
git add lean-toolchain
508508
lake update batteries
509509
git add lake-manifest.json
510-
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
510+
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
511511
fi
512512
513513
- name: Push changes
@@ -558,7 +558,7 @@ jobs:
558558
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
559559
git add lean-toolchain
560560
git add lakefile.lean lake-manifest.json
561-
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
561+
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
562562
else
563563
echo "Branch already exists, updating lean-toolchain."
564564
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
@@ -568,7 +568,7 @@ jobs:
568568
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
569569
git add lean-toolchain
570570
git add lake-manifest.json
571-
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
571+
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
572572
fi
573573
574574
- name: Push changes

script/Shake.lean

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,11 @@ structure State where
131131
`transDeps[i]` is the (non-reflexive) transitive closure of `mods[i].imports`. More specifically,
132132
* `j ∈ transDeps[i].pub` if `i -(public import)->+ j`
133133
* `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
134-
* `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
135-
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
136-
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
137-
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
134+
* `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
135+
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
136+
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
137+
* `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
138+
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
138139
-/
139140
transDeps : Array Needs := #[]
140141
/--
@@ -162,21 +163,24 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
162163
-- `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
163164
transImps := transImps.union .priv {j} |>.union .priv (impTransImps.get .pub)
164165
if imp.importAll then
165-
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
166-
transImps := transImps.union .priv (impTransImps.get .pub)
166+
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
167+
transImps := transImps.union .priv (impTransImps.get .pub ∪ impTransImps.get .priv)
167168

168-
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
169+
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
169170
if imp.isExported then
170171
transImps := transImps.union .metaPub (impTransImps.get .metaPub)
171172
if imp.isMeta then
172173
transImps := transImps.union .metaPub {j} |>.union .metaPub (impTransImps.get .pub ∪ impTransImps.get .metaPub)
173174

174175
if !imp.isExported then
175176
if imp.isMeta then
176-
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
177+
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
177178
transImps := transImps.union .metaPriv {j} |>.union .metaPriv (impTransImps.get .pub ∪ impTransImps.get .metaPub)
178179
if imp.importAll then
179-
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
180+
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
181+
transImps := transImps.union .metaPriv (impTransImps.get .metaPub ∪ impTransImps.get .metaPriv)
182+
else
183+
-- `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
180184
transImps := transImps.union .metaPriv (impTransImps.get .metaPub)
181185

182186
transImps
@@ -185,7 +189,8 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
185189
def calcNeeds (env : Environment) (i : ModuleIdx) : Needs := Id.run do
186190
let mut needs := default
187191
for ci in env.header.moduleData[i]!.constants do
188-
let pubCI? := env.setExporting true |>.find? ci.name
192+
-- Added guard for cases like `structure` that are still exported even if private
193+
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
189194
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
190195
needs := visitExpr k ci.type needs
191196
if let some e := ci.value? (allowOpaque := true) then
@@ -216,7 +221,8 @@ def getExplanations (env : Environment) (i : ModuleIdx) :
216221
Std.HashMap (ModuleIdx × NeedsKind) (Option (Name × Name)) := Id.run do
217222
let mut deps := default
218223
for ci in env.header.moduleData[i]!.constants do
219-
let pubCI? := env.setExporting true |>.find? ci.name
224+
-- Added guard for cases like `structure` that are still exported even if private
225+
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
220226
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
221227
deps := visitExpr k ci.name ci.type deps
222228
if let some e := ci.value? (allowOpaque := true) then
@@ -286,16 +292,16 @@ and `endPos` is the position of the end of the header.
286292
-/
287293
def parseHeaderFromString (text path : String) :
288294
IO (System.FilePath × Parser.InputContext ×
289-
TSyntaxArray ``Parser.Module.import × String.Pos) := do
295+
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
290296
let inputCtx := Parser.mkInputContext text path
291297
let (header, parserState, msgs) ← Parser.parseHeader inputCtx
292298
if !msgs.toList.isEmpty then -- skip this file if there are parse errors
293299
msgs.forM fun msg => msg.toString >>= IO.println
294300
throw <| .userError "parse errors in file"
295301
-- the insertion point for `add` is the first newline after the imports
296302
let insertion := header.raw.getTailPos?.getD parserState.pos
297-
let insertion := text.findAux (· == '\n') text.endPos insertion + 1
298-
pure (path, inputCtx, .mk header.raw[2].getArgs, insertion)
303+
let insertion := text.findAux (· == '\n') text.endPos insertion + '\n'
304+
pure (path, inputCtx, header, insertion)
299305

300306
/-- Parse a source file to extract the location of the import lines, for edits and error messages.
301307
@@ -304,13 +310,18 @@ and `endPos` is the position of the end of the header.
304310
-/
305311
def parseHeader (srcSearchPath : SearchPath) (mod : Name) :
306312
IO (System.FilePath × Parser.InputContext ×
307-
TSyntaxArray ``Parser.Module.import × String.Pos) := do
313+
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
308314
-- Parse the input file
309315
let some path ← srcSearchPath.findModuleWithExt "lean" mod
310316
| throw <| .userError s!"error: failed to find source file for {mod}"
311317
let text ← IO.FS.readFile path
312318
parseHeaderFromString text path.toString
313319

320+
def decodeHeader : TSyntax ``Parser.Module.header → Option (TSyntax `module) × Option (TSyntax `prelude) × TSyntaxArray ``Parser.Module.import
321+
| `(Parser.Module.header| $[module%$moduleTk?]? $[prelude%$preludeTk?]? $imports*) =>
322+
(moduleTk?.map .mk, preludeTk?.map .mk, imports)
323+
| _ => unreachable!
324+
314325
def decodeImport : TSyntax ``Parser.Module.import → Import
315326
| `(Parser.Module.import| $[public%$pubTk?]? $[meta%$metaTk?]? import $[all%$allTk?]? $id) =>
316327
{ module := id.getId, isExported := pubTk?.isSome, isMeta := metaTk?.isSome, importAll := allTk?.isSome }
@@ -326,11 +337,20 @@ def decodeImport : TSyntax ``Parser.Module.import → Import
326337
* `addOnly`: if true, only add missing imports, do not remove unused ones
327338
-/
328339
def visitModule (srcSearchPath : SearchPath)
329-
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits)
340+
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits) (headerStx : TSyntax ``Parser.Module.header)
330341
(addOnly := false) (githubStyle := false) (explain := false) : StateT State IO Edits := do
331342
let s ← get
332343
-- Do transitive reduction of `needs` in `deps`.
333344
let mut deps := needs
345+
let (_, prelude?, imports) := decodeHeader headerStx
346+
if prelude?.isNone then
347+
deps := deps.union .pub {s.env.getModuleIdx? `Init |>.get!}
348+
for imp in imports do
349+
if addOnly || imp.raw.getTrailing?.any (·.toString.toSlice.contains "shake: keep") then
350+
let imp := decodeImport imp
351+
let j := s.env.getModuleIdx? imp.module |>.get!
352+
let k := NeedsKind.ofImport imp
353+
deps := deps.union k {j}
334354
for j in [0:s.mods.size] do
335355
let transDeps := s.transDeps[j]!
336356
for k in NeedsKind.all do
@@ -354,7 +374,8 @@ def visitModule (srcSearchPath : SearchPath)
354374
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
355375
else
356376
let k := NeedsKind.ofImport imp
357-
if !addOnly && !deps.has k j && !deps.has { k with isExported := false } j then
377+
-- A private import should also be removed if the public version is needed
378+
if !deps.has k j || !k.isExported && deps.has { k with isExported := true } j then
358379
toRemove := toRemove.push imp
359380
else
360381
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
@@ -385,7 +406,8 @@ def visitModule (srcSearchPath : SearchPath)
385406

386407
if githubStyle then
387408
try
388-
let (path, inputCtx, imports, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
409+
let (path, inputCtx, stx, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
410+
let (_, _, imports) := decodeHeader stx
389411
for stx in imports do
390412
if toRemove.any fun imp => imp == decodeImport stx then
391413
let pos := inputCtx.fileMap.toPosition stx.raw.getPos?.get!
@@ -529,41 +551,51 @@ def main (args : List String) : IO UInt32 := do
529551
let needs := s.mods.mapIdx fun i _ =>
530552
Task.spawn fun _ => calcNeeds s.env i
531553

554+
-- Parse headers in parallel
555+
let headers ← s.mods.mapIdxM fun i _ =>
556+
BaseIO.asTask (parseHeader srcSearchPath s.modNames[i]! |>.toBaseIO)
557+
532558
if args.fix then
533559
println! "The following changes will be made automatically:"
534560

535561
-- Check all selected modules
536562
let mut edits : Edits := ∅
537563
let mut revNeeds : Needs := default
538-
for i in [0:s.mods.size], t in needs do
539-
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!) srcSearchPath i t.get revNeeds edits args.githubStyle args.explain
540-
if isExtraRevModUse s.env i then
541-
revNeeds := revNeeds.union .priv {i}
564+
for i in [0:s.mods.size], t in needs, header in headers do
565+
match header.get with
566+
| .ok (_, _, stx, _) =>
567+
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!)
568+
srcSearchPath i t.get revNeeds edits stx args.githubStyle args.explain
569+
if isExtraRevModUse s.env i then
570+
revNeeds := revNeeds.union .priv {i}
571+
| .error e =>
572+
println! e.toString
542573

543574
if !args.fix then
544575
-- return error if any issues were found
545576
return if edits.isEmpty then 0 else 1
546577

547578
-- Apply the edits to existing files
548-
let count ← edits.foldM (init := 0) fun count mod (remove, add) => do
579+
let mut count := 0
580+
for mod in s.modNames, header? in headers do
581+
let some (remove, add) := edits[mod]? | continue
549582
let add : Array Import := add.qsortOrd
550583

551584
-- Parse the input file
552-
let (path, inputCtx, imports, insertion) ←
553-
try parseHeader srcSearchPath mod
554-
catch e => println! e.toString; return count
585+
let .ok (path, inputCtx, stx, insertion) := header?.get | continue
586+
let (_, _, imports) := decodeHeader stx
555587
let text := inputCtx.fileMap.source
556588

557589
-- Calculate the edit result
558-
let mut pos : String.Pos := 0
590+
let mut pos : String.Pos.Raw := 0
559591
let mut out : String := ""
560592
let mut seen : Std.HashSet Import := {}
561593
for stx in imports do
562594
let mod := decodeImport stx
563595
if remove.contains mod || seen.contains mod then
564596
out := out ++ text.extract pos stx.raw.getPos?.get!
565597
-- We use the end position of the syntax, but include whitespace up to the first newline
566-
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + 1
598+
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + '\n'
567599
seen := seen.insert mod
568600
out := out ++ text.extract pos insertion
569601
for mod in add do
@@ -573,7 +605,7 @@ def main (args : List String) : IO UInt32 := do
573605
out := out ++ text.extract insertion text.rawEndPos
574606

575607
IO.FS.writeFile path out
576-
return count + 1
608+
count := count + 1
577609

578610
-- Since we throw an error upon encountering issues, we can be sure that everything worked
579611
-- if we reach this point of the script.

src/Init.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public import Init.ByCases
1414
public import Init.RCases
1515
public import Init.Core
1616
public import Init.Control
17-
public import Init.Data.Basic
1817
public import Init.WF
1918
public import Init.WFTactics
2019
public import Init.Data

src/Init/ByCases.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,10 @@ theorem apply_ite (f : α → β) (P : Prop) [Decidable P] (x y : α) :
4444
/-- A `dite` whose results do not actually depend on the condition may be reduced to an `ite`. -/
4545
@[simp] theorem dite_eq_ite [Decidable P] :
4646
(dite P (fun _ => a) (fun _ => b)) = ite P a b := rfl
47+
48+
-- Remark: dite and ite are "defally equal" when we ignore the proofs.
49+
@[deprecated dite_eq_ite (since := "2025-10-29")]
50+
theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) : dite c (fun _ => t) (fun _ => e) = ite c t e :=
51+
match h with
52+
| isTrue _ => rfl
53+
| isFalse _ => rfl

src/Init/Classical.lean

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,6 @@ theorem not_imp_iff_and_not : ¬(a → b) ↔ a ∧ ¬b := Decidable.not_imp_iff
181181

182182
theorem not_and_iff_not_or_not : ¬(a ∧ b) ↔ ¬a ∨ ¬b := Decidable.not_and_iff_not_or_not
183183

184-
@[deprecated not_and_iff_not_or_not (since := "2025-03-18")]
185-
abbrev not_and_iff_or_not_not := @not_and_iff_not_or_not
186-
187184
theorem not_iff : ¬(a ↔ b) ↔ (¬a ↔ b) := Decidable.not_iff
188185

189186
@[simp] theorem imp_iff_left_iff : (b ↔ a → b) ↔ a ∨ b := Decidable.imp_iff_left_iff

src/Init/Control/Basic.lean

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α
4545
forIn x b f = forIn' x b (fun x h => binderNameHint x f <| binderNameHint h () <| f x) := by
4646
rfl
4747

48-
@[deprecated forIn_eq_forIn' (since := "2025-04-04")]
49-
abbrev forIn_eq_forin' := @forIn_eq_forIn'
50-
5148
/--
5249
Extracts the value from a `ForInStep`, ignoring whether it is `ForInStep.done` or `ForInStep.yield`.
5350
-/

src/Init/Control/Lawful/Basic.lean

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ =>
170170
theorem map_congr [Functor m] {x : m α} {f g : α → β} (h : ∀ a, f a = g a) : (f <$> x : m β) = g <$> x := by
171171
simp [funext h]
172172

173+
@[deprecated seq_eq_bind_map (since := "2025-10-26")]
173174
theorem seq_eq_bind {α β : Type u} [Monad m] [LawfulMonad m] (mf : m (α → β)) (x : m α) : mf <*> x = mf >>= fun f => f <$> x := by
174175
rw [bind_map]
175176

@@ -255,20 +256,4 @@ instance : LawfulMonad Id := by
255256
@[simp] theorem run_seqLeft (x y : Id α) : (x <* y).run = x.run := rfl
256257
@[simp] theorem run_seq (f : Id (α → β)) (x : Id α) : (f <*> x).run = f.run x.run := rfl
257258

258-
-- These lemmas are bad as they abuse the defeq of `Id α` and `α`
259-
@[deprecated run_map (since := "2025-03-05")] theorem map_eq (x : Id α) (f : α → β) : f <$> x = f x := rfl
260-
@[deprecated run_bind (since := "2025-03-05")] theorem bind_eq (x : Id α) (f : α → id β) : x >>= f = f x := rfl
261-
@[deprecated run_pure (since := "2025-03-05")] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
262-
263259
end Id
264-
265-
/-! # Option -/
266-
267-
instance : LawfulMonad Option := LawfulMonad.mk'
268-
(id_map := fun x => by cases x <;> rfl)
269-
(pure_bind := fun _ _ => rfl)
270-
(bind_assoc := fun x _ _ => by cases x <;> rfl)
271-
(bind_pure_comp := fun _ x => by cases x <;> rfl)
272-
273-
instance : LawfulApplicative Option := inferInstance
274-
instance : LawfulFunctor Option := inferInstance

0 commit comments

Comments
 (0)