@@ -37,9 +37,9 @@ property as is will give us an error because we do not have an instance
3737of `Shrinkable MyType` and `SampleableExt MyType`. We can define one as follows:
3838```lean
3939instance : Shrinkable MyType where
40- shrink := λ ⟨x,y,h⟩ =>
40+ shrink := fun ⟨x,y,h⟩ =>
4141 let proxy := Shrinkable.shrink (x, y - x)
42- proxy.map (λ ⟨⟨fst, snd⟩, ha⟩ => ⟨⟨fst, fst + snd, sorry⟩, sorry⟩)
42+ proxy.map (fun ⟨⟨fst, snd⟩, ha⟩ => ⟨⟨fst, fst + snd, sorry⟩, sorry⟩)
4343instance : SampleableExt MyType :=
4444 SampleableExt.mkSelfContained do
4545 let x ← SampleableExt.interpSample Nat
@@ -98,7 +98,17 @@ structure Configuration where
9898 traceShrinkCandidates : Bool := false
9999 randomSeed : Option Nat := none
100100 quiet : Bool := false
101- deriving Inhabited
101+
102+ namespace Configuration
103+
104+ /-- A configuration with all the trace options enabled, useful for debugging. -/
105+ def verbose : Configuration where
106+ traceDiscarded := true
107+ traceSuccesses := true
108+ traceShrink := true
109+ traceShrinkCandidates := true
110+
111+ end Configuration
102112
103113/--
104114`PrintableProp p` allows one to print a proposition so that
@@ -136,8 +146,8 @@ def combine {p q : Prop} : PSum Unit (p → q) → PSum Unit p → PSum Unit q
136146
137147/-- Combine the test result for properties `p` and `q` to create a test for their conjunction. -/
138148def and : TestResult p → TestResult q → TestResult (p ∧ q)
139- | failure h xs n, _ => failure (λ h2 => h h2.left) xs n
140- | _, failure h xs n => failure (λ h2 => h h2.right) xs n
149+ | failure h xs n, _ => failure (fun h2 => h h2.left) xs n
150+ | _, failure h xs n => failure (fun h2 => h h2.right) xs n
141151| success h1, success h2 => success $ combine (combine (PSum.inr And.intro) h1) h2
142152| gaveUp n, gaveUp m => gaveUp $ n + m
143153| gaveUp n, _ => gaveUp n
@@ -146,7 +156,7 @@ def and : TestResult p → TestResult q → TestResult (p ∧ q)
146156/-- Combine the test result for properties `p` and `q` to create a test for their disjunction. -/
147157def or : TestResult p → TestResult q → TestResult (p ∨ q)
148158| failure h1 xs n, failure h2 ys m =>
149- let h3 := λ h =>
159+ let h3 := fun h =>
150160 match h with
151161 | Or.inl h3 => h1 h3
152162 | Or.inr h3 => h2 h3
@@ -186,39 +196,29 @@ def addVarInfo [Repr γ] (var : String) (x : γ) (h : q → p) (r : TestResult p
186196 addInfo s! "{ var} := { repr x} " h r p
187197
188198def isFailure : TestResult p → Bool
189- | failure _ _ _ => true
190- | _ => false
199+ | failure .. => true
200+ | _ => false
191201
192202end TestResult
193203
194- namespace Configuration
195-
196- /-- A configuration with all the trace options enabled, useful for debugging. -/
197- def verbose : Configuration where
198- traceDiscarded := true
199- traceSuccesses := true
200- traceShrink := true
201- traceShrinkCandidates := true
202-
203- end Configuration
204-
205204namespace Checkable
206205
207206open TestResult
208207
209208def runProp (p : Prop ) [Checkable p] : Configuration → Bool → Gen (TestResult p) := Checkable.run
210209
211210/-- A `dbgTrace` with special formatting -/
212- def slimTrace [Pure m] (s : String) : m PUnit := dbgTrace s! "[SlimCheck: { s} ]" (λ _ => pure ())
211+ def slimTrace [Pure m] (s : String) : m Unit :=
212+ dbgTrace s! "[SlimCheck: { s} ]" fun _ => pure ()
213213
214214instance andCheckable [Checkable p] [Checkable q] : Checkable (p ∧ q) where
215- run := λ cfg min => do
215+ run := fun cfg min => do
216216 let xp ← runProp p cfg min
217217 let xq ← runProp q cfg min
218218 pure $ and xp xq
219219
220220instance orCheckable [Checkable p] [Checkable q] : Checkable (p ∨ q) where
221- run := λ cfg min => do
221+ run := fun cfg min => do
222222 let xp ← runProp p cfg min
223223 -- As a little performance optimization we can just not run the second
224224 -- test if the first succeeds
@@ -229,44 +229,40 @@ instance orCheckable [Checkable p] [Checkable q] : Checkable (p ∨ q) where
229229 let xq ← runProp q cfg min
230230 pure $ or xp xq
231231
232- -- TODO(Winston): Move
233- protected theorem key : (a ↔ b) ↔ (a ∧ b) ∨ (¬ a ∧ ¬ b) :=
234- by constructor
235- · intro h; rw [h]
236- by_cases h : b
237- · exact Or.inl <| And.intro h h
238- · exact Or.inr <| And.intro h h
239- · intro h
240- match h with
241- | Or.inl h => exact Iff.intro (λ _ => h.2 ) (λ _ => h.1 )
242- | Or.inr h => exact Iff.intro (λ a => False.elim $ h.1 a) (λ b => False.elim $ h.2 b)
243-
244232instance iffCheckable [Checkable ((p ∧ q) ∨ (¬ p ∧ ¬ q))] : Checkable (p ↔ q) where
245- run := λ cfg min => do
233+ run := fun cfg min => do
246234 let h ← runProp ((p ∧ q) ∨ (¬ p ∧ ¬ q)) cfg min
247- pure $ iff Checkable.key h
235+ have key {a b} : (a ↔ b) ↔ (a ∧ b) ∨ (¬ a ∧ ¬ b) := by
236+ constructor
237+ · intro h; rw [h]
238+ by_cases h : b
239+ · exact .inl $ .intro h h
240+ · exact .inr $ .intro h h
241+ · intro h
242+ match h with
243+ | .inl h => exact Iff.intro (fun _ => h.2 ) (fun _ => h.1 )
244+ | .inr h => exact Iff.intro (fun a => False.elim $ h.1 a) (fun b => False.elim $ h.2 b)
245+ pure $ iff key h
248246
249247instance decGuardCheckable [PrintableProp p] [Decidable p] {β : p → Prop } [∀ h, Checkable (β h)] : Checkable (NamedBinder var $ ∀ h, β h) where
250- run := λ cfg min => do
248+ run := fun cfg min => do
251249 if h : p then
252250 let res := (runProp (β h) cfg min)
253251 let s := printProp p
254- (λ r => addInfo s! "guard: { s} " (· $ h) r (PSum.inr $ λ q _ => q)) <$> res
252+ (fun r => addInfo s! "guard: { s} " (· $ h) r (PSum.inr $ fun q _ => q)) <$> res
255253 else if cfg.traceDiscarded || cfg.traceSuccesses then
256- let res := (λ _ => pure $ gaveUp 1 )
254+ let res := (fun _ => pure $ gaveUp 1 )
257255 let s := printProp p
258256 slimTrace s! "discard: Guard { s} does not hold" ; res
259257 else
260258 pure $ gaveUp 1
261259
262260instance forallTypesCheckable {f : Type → Prop } [Checkable (f Int)] : Checkable (NamedBinder var $ ∀ x, f x) where
263- run := λ cfg min => do
261+ run := fun cfg min => do
264262 let r ← runProp (f Int) cfg min
265263 pure $ addVarInfo var "ℤ" (· $ Int) r
266264
267- /--
268- Format the counter-examples found in a test failure.
269- -/
265+ /-- Format the counter-examples found in a test failure. -/
270266def formatFailure (s : String) (xs : List String) (n : Nat) : String :=
271267 let counter := "\n " .intercalate xs
272268 let parts := [
@@ -278,24 +274,19 @@ def formatFailure (s : String) (xs : List String) (n : Nat) : String :=
278274 ]
279275 "\n " .intercalate parts
280276
281- /--
282- Increase the number of shrinking steps in a test result.
283- -/
277+ /-- Increase the number of shrinking steps in a test result. -/
284278def addShrinks (n : Nat) : TestResult p → TestResult p
285279| TestResult.failure p xs m => TestResult.failure p xs (m + n)
286280| p => p
287281
288- -- TODO(Winston): Move
289- instance [Inhabited (m (Option α))]: Inhabited (OptionT m α) where
290- default := .mk default
291-
292282/-- Shrink a counter-example `x` by using `Shrinkable.shrink x`, picking the first
293283candidate that falsifies a property and recursively shrinking that one.
294284The process is guaranteed to terminate because `shrink x` produces
295285a proof that all the values it produces are smaller (according to `SizeOf`)
296286than `x`. -/
297- partial def minimizeAux [SampleableExt α] {β : α → Prop } [∀ x, Checkable (β x)] (cfg : Configuration) (var : String)
298- (x : SampleableExt.proxy α) (n : Nat) : OptionT Gen (Σ x, TestResult (β (SampleableExt.interp x))) := do
287+ def minimizeAux [SampleableExt α] {β : α → Prop } [∀ x, Checkable (β x)]
288+ (cfg : Configuration) (var : String) (x : SampleableExt.proxy α) (n : Nat) :
289+ OptionT Gen (Σ x, TestResult (β (SampleableExt.interp x))) := do
299290 let candidates := SampleableExt.shrink.shrink x
300291 if cfg.traceShrinkCandidates then
301292 slimTrace s! "Candidates for { var} := { repr x} :\n { repr candidates} "
@@ -327,12 +318,12 @@ def minimize [SampleableExt α] {β : α → Prop} [∀ x, Checkable (β x)] (cf
327318/-- Test a universal property by creating a sample of the right type and instantiating the
328319bound variable with it. -/
329320instance varCheckable [SampleableExt α] {β : α → Prop } [∀ x, Checkable (β x)] : Checkable (NamedBinder var $ ∀ x : α, β x) where
330- run := λ cfg min => do
321+ run := fun cfg min => do
331322 let x ← SampleableExt.sample
332323 if cfg.traceSuccesses || cfg.traceDiscarded then
333324 slimTrace s! "{ var} := { repr x} "
334325 let r ← Checkable.runProp (β $ SampleableExt.interp x) cfg false
335- let ⟨finalX, finalR⟩ ←
326+ let ⟨finalX, finalR⟩ ←
336327 if isFailure r then
337328 if cfg.traceSuccesses then
338329 slimTrace s! "{ var} := { repr x} is a failure"
@@ -348,21 +339,21 @@ instance varCheckable [SampleableExt α] {β : α → Prop} [∀ x, Checkable (
348339instance propVarCheckable {β : Prop → Prop } [∀ b : Bool, Checkable (β b)] :
349340 Checkable (NamedBinder var $ ∀ p : Prop , β p)
350341where
351- run := λ cfg min =>
352- imp (λ h (b : Bool) => h b) <$> Checkable.runProp (NamedBinder var $ ∀ b : Bool, β b) cfg min
342+ run := fun cfg min =>
343+ imp (fun h (b : Bool) => h b) <$> Checkable.runProp (NamedBinder var $ ∀ b : Bool, β b) cfg min
353344
354345instance (priority := high) unusedVarCheckable [Nonempty α] [Checkable β] :
355346 Checkable (NamedBinder var $ ∀ _x : α, β)
356347where
357- run := λ cfg min => do
348+ run := fun cfg min => do
358349 if cfg.traceDiscarded || cfg.traceSuccesses then
359350 slimTrace s! "{ var} is unused"
360351 let r ← Checkable.runProp β cfg min
361352 let finalR := addInfo s! "{ var} is irrelevant (unused)" id r
362- pure $ imp (· $ Classical.ofNonempty) finalR (PSum.inr $ λ x _ => x)
353+ pure $ imp (· $ Classical.ofNonempty) finalR (PSum.inr $ fun x _ => x)
363354
364355instance (priority := low) decidableCheckable {p : Prop } [PrintableProp p] [Decidable p] : Checkable p where
365- run := λ _ _ =>
356+ run := fun _ _ =>
366357 if h : p then
367358 pure $ success (PSum.inr h)
368359 else
@@ -416,34 +407,33 @@ open TestResult
416407
417408/-- Execute `cmd` and repeat every time the result is `gave_up` (at most `n` times). -/
418409def retry (cmd : Rand (TestResult p)) : Nat → Rand (TestResult p)
419- | 0 => pure $ TestResult.gaveUp 1
420- | n+1 => do
421- let r ← cmd
422- match r with
423- | success hp => pure $ success hp
424- | TestResult.failure h xs n => pure $ failure h xs n
425- | gaveUp _ => retry cmd n
410+ | 0 => pure $ TestResult.gaveUp 1
411+ | n + 1 => do match ← cmd with
412+ | success hp => pure $ success hp
413+ | TestResult.failure h xs n => pure $ failure h xs n
414+ | gaveUp _ => retry cmd n
426415
427416/-- Count the number of times the test procedure gave up. -/
428417def giveUp (x : Nat) : TestResult p → TestResult p
429- | success (PSum.inl ()) => gaveUp x
430- | success (PSum.inr p) => success $ (PSum.inr p)
431- | gaveUp n => gaveUp $ n + x
432- | TestResult.failure h xs n => failure h xs n
418+ | success (PSum.inl ()) => gaveUp x
419+ | success (PSum.inr p) => success $ (PSum.inr p)
420+ | gaveUp n => gaveUp $ n + x
421+ | TestResult.failure h xs n => failure h xs n
433422
434423/-- Try `n` times to find a counter-example for `p`. -/
435- def Checkable.runSuiteAux (p : Prop ) [Checkable p] (cfg : Configuration) : TestResult p → Nat → Rand (TestResult p)
436- | r, 0 => pure r
437- | r, n+1 => do
438- let size := (cfg.numInst - n - 1 ) * cfg.maxSize / cfg.numInst
439- if cfg.traceSuccesses then
440- slimTrace s! "New sample"
441- slimTrace s! "Retrying up to { cfg.numRetries} times until guards hold"
442- let x ← retry (ReaderT.run (Checkable.runProp p cfg true ) ⟨size⟩) cfg.numRetries
443- match x with
444- | (success (PSum.inl ())) => runSuiteAux p cfg r n
445- | (gaveUp g) => runSuiteAux p cfg (giveUp g r) n
446- | _ => pure $ x
424+ def Checkable.runSuiteAux (p : Prop ) [Checkable p] (cfg : Configuration) (r : TestResult p) :
425+ Nat → Rand (TestResult p)
426+ | 0 => pure r
427+ | n + 1 => do
428+ let size := (cfg.numInst - n - 1 ) * cfg.maxSize / cfg.numInst
429+ if cfg.traceSuccesses then
430+ slimTrace s! "New sample"
431+ slimTrace s! "Retrying up to { cfg.numRetries} times until guards hold"
432+ let x ← retry (ReaderT.run (Checkable.runProp p cfg true ) ⟨size⟩) cfg.numRetries
433+ match x with
434+ | (success (PSum.inl ())) => runSuiteAux p cfg r n
435+ | (gaveUp g) => runSuiteAux p cfg (giveUp g r) n
436+ | _ => pure $ x
447437
448438/-- Try to find a counter-example of `p`. -/
449439def Checkable.runSuite (p : Prop ) [Checkable p] (cfg : Configuration := {}) : Rand (TestResult p) :=
@@ -464,8 +454,7 @@ open Lean
464454/-- Traverse the syntax of a proposition to find universal quantifiers
465455quantifiers and add `NamedBinder` annotations next to them. -/
466456partial def addDecorations (e : Expr) : Expr :=
467- e.replace $ λ expr =>
468- match expr with
457+ e.replace fun expr => match expr with
469458 | Expr.forallE name type body data =>
470459 let n := name.toString
471460 let newType := addDecorations type
@@ -479,9 +468,7 @@ that the goal should be satisfied with a proposition equivalent to `p`
479468with added annotations. -/
480469abbrev DecorationsOf (_p : Prop ) := Prop
481470
482- open Elab.Tactic
483- open Meta
484-
471+ open Elab.Tactic in
485472/-- In a goal of the shape `⊢ DecorationsOf p`, `mk_decoration` examines
486473the syntax of `p` and adds `NamedBinder` around universal quantifications
487474to improve error messages. This tool can be used in the declaration of a
@@ -501,10 +488,9 @@ end Decorations
501488
502489open Decorations in
503490/-- Run a test suite for `p` and throw an exception if `p` does not not hold.-/
504- def Checkable.check (p : Prop ) (cfg : Configuration := {}) (p' : Decorations.DecorationsOf p := by mk_decorations) [Checkable p'] : IO PUnit := do
505- let x ← Checkable.checkIO p' cfg
506- go p' x where /-- HACK: https://github.com/leanprover/lean4/issues/1247 -/ go p' (x : TestResult p') : IO PUnit := do
507- match x with
491+ def Checkable.check (p : Prop ) (cfg : Configuration := {})
492+ (p' : DecorationsOf p := by mk_decorations) [Checkable p'] : IO Unit := do
493+ match ← Checkable.checkIO p' cfg with
508494 | TestResult.success _ => if !cfg.quiet then IO.println "Success" else pure ()
509495 | TestResult.gaveUp n => if !cfg.quiet then IO.println s! "Gave up { n} times"
510496 | TestResult.failure _ xs n => throw (IO.userError $ formatFailure "Found problems!" xs n)
0 commit comments