File: Mathlib/Testing/SlimCheck/Sampleable.lean

full_name: SlimCheck.Shrinkable
code: /-- Given an example `x : α`, `Shrinkable α` gives us a way to shrink it
and suggest simpler examples. -/
class Shrinkable (α : Type u) where
  shrink : (x : α) → List α := fun _ ↦ []
goal: Type u

full_name: SlimCheck.Shrinkable.shrink
code: /-- Given an example `x : α`, `Shrinkable α` gives us a way to shrink it
and suggest simpler examples. -/
class Shrinkable (α : Type u) where
  shrink : (x : α) → List α := fun _ ↦ []
goal: List α

full_name: SlimCheck.SampleableExt.interp
code: /-- `SampleableExt` can be used in two ways. The first (and most common)
is to simply generate values of a type directly using the `Gen` monad,
if this is what you want to do then `SampleableExt.mkSelfContained` is
the way to go.

Furthermore it makes it possible to express generators for types that
do not lend themselves to introspection, such as `ℕ → ℕ`.
If we test a quantification over functions the
counter-examples cannot be shrunken or printed meaningfully.
For that purpose, `SampleableExt` provides a proxy representation
`proxy` that can be printed and shrunken as well
as interpreted (using `interp`) as an object of the right type. -/
class SampleableExt (α : Sort u) where
  proxy : Type v
  [proxyRepr : Repr proxy]
  [shrink : Shrinkable proxy]
  sample : Gen proxy
  interp : proxy → α
goal: SlimCheck.SampleableExt.proxy α → α

full_name: SlimCheck.SampleableExt
code: /-- `SampleableExt` can be used in two ways. The first (and most common)
is to simply generate values of a type directly using the `Gen` monad,
if this is what you want to do then `SampleableExt.mkSelfContained` is
the way to go.

Furthermore it makes it possible to express generators for types that
do not lend themselves to introspection, such as `ℕ → ℕ`.
If we test a quantification over functions the
counter-examples cannot be shrunken or printed meaningfully.
For that purpose, `SampleableExt` provides a proxy representation
`proxy` that can be printed and shrunken as well
as interpreted (using `interp`) as an object of the right type. -/
class SampleableExt (α : Sort u) where
  proxy : Type v
  [proxyRepr : Repr proxy]
  [shrink : Shrinkable proxy]
  sample : Gen proxy
  interp : proxy → α
goal: Sort (max u (v + 2))

full_name: SlimCheck.SampleableExt.proxy
code: /-- `SampleableExt` can be used in two ways. The first (and most common)
is to simply generate values of a type directly using the `Gen` monad,
if this is what you want to do then `SampleableExt.mkSelfContained` is
the way to go.

Furthermore it makes it possible to express generators for types that
do not lend themselves to introspection, such as `ℕ → ℕ`.
If we test a quantification over functions the
counter-examples cannot be shrunken or printed meaningfully.
For that purpose, `SampleableExt` provides a proxy representation
`proxy` that can be printed and shrunken as well
as interpreted (using `interp`) as an object of the right type. -/
class SampleableExt (α : Sort u) where
  proxy : Type v
  [proxyRepr : Repr proxy]
  [shrink : Shrinkable proxy]
  sample : Gen proxy
  interp : proxy → α
goal: Type v

full_name: SlimCheck.SampleableExt.proxyRepr
code: /-- `SampleableExt` can be used in two ways. The first (and most common)
is to simply generate values of a type directly using the `Gen` monad,
if this is what you want to do then `SampleableExt.mkSelfContained` is
the way to go.

Furthermore it makes it possible to express generators for types that
do not lend themselves to introspection, such as `ℕ → ℕ`.
If we test a quantification over functions the
counter-examples cannot be shrunken or printed meaningfully.
For that purpose, `SampleableExt` provides a proxy representation
`proxy` that can be printed and shrunken as well
as interpreted (using `interp`) as an object of the right type. -/
class SampleableExt (α : Sort u) where
  proxy : Type v
  [proxyRepr : Repr proxy]
  [shrink : Shrinkable proxy]
  sample : Gen proxy
  interp : proxy → α
goal: Repr (SlimCheck.SampleableExt.proxy α)

full_name: SlimCheck.SampleableExt.shrink
code: /-- `SampleableExt` can be used in two ways. The first (and most common)
is to simply generate values of a type directly using the `Gen` monad,
if this is what you want to do then `SampleableExt.mkSelfContained` is
the way to go.

Furthermore it makes it possible to express generators for types that
do not lend themselves to introspection, such as `ℕ → ℕ`.
If we test a quantification over functions the
counter-examples cannot be shrunken or printed meaningfully.
For that purpose, `SampleableExt` provides a proxy representation
`proxy` that can be printed and shrunken as well
as interpreted (using `interp`) as an object of the right type. -/
class SampleableExt (α : Sort u) where
  proxy : Type v
  [proxyRepr : Repr proxy]
  [shrink : Shrinkable proxy]
  sample : Gen proxy
  interp : proxy → α
goal: SlimCheck.Shrinkable (SlimCheck.SampleableExt.proxy α)

full_name: SlimCheck.SampleableExt.sample
code: /-- `SampleableExt` can be used in two ways. The first (and most common)
is to simply generate values of a type directly using the `Gen` monad,
if this is what you want to do then `SampleableExt.mkSelfContained` is
the way to go.

Furthermore it makes it possible to express generators for types that
do not lend themselves to introspection, such as `ℕ → ℕ`.
If we test a quantification over functions the
counter-examples cannot be shrunken or printed meaningfully.
For that purpose, `SampleableExt` provides a proxy representation
`proxy` that can be printed and shrunken as well
as interpreted (using `interp`) as an object of the right type. -/
class SampleableExt (α : Sort u) where
  proxy : Type v
  [proxyRepr : Repr proxy]
  [shrink : Shrinkable proxy]
  sample : Gen proxy
  interp : proxy → α
goal: SlimCheck.Gen (SlimCheck.SampleableExt.proxy α)

full_name: SlimCheck.SampleableExt.mkSelfContained
code: /-- Use to generate instance whose purpose is to simply generate values
of a type directly using the `Gen` monad -/
def mkSelfContained [Repr α] [Shrinkable α] (sample : Gen α) : SampleableExt α 
goal: SlimCheck.SampleableExt α

full_name: SlimCheck.SampleableExt.interpSample
code: /-- First samples a proxy value and interprets it. Especially useful if
the proxy and target type are the same. -/
def interpSample (α : Type u) [SampleableExt α] : Gen α 
goal: SlimCheck.Gen α

full_name: SlimCheck.Nat.shrink
code: /-- `Nat.shrink' n` creates a list of smaller natural numbers by
successively dividing `n` by 2 . For example, `Nat.shrink 5 = [2, 1, 0]`. -/
def Nat.shrink (n : Nat) : List Nat 
goal: List ℕ

full_name: SlimCheck.Nat.shrinkable
code: instance Nat.shrinkable : Shrinkable Nat 
goal: SlimCheck.Shrinkable ℕ

full_name: SlimCheck.Fin.shrinkable
code: instance Fin.shrinkable {n : Nat} : Shrinkable (Fin n.succ) 
goal: SlimCheck.Shrinkable (Fin n.succ)

full_name: SlimCheck.Int.shrinkable
code: /-- `Int.shrinkable` operates like `Nat.shrinkable` but also includes the negative variants. -/
instance Int.shrinkable : Shrinkable Int 
goal: SlimCheck.Shrinkable ℤ

full_name: SlimCheck.Rat.shrinkable
code: instance Rat.shrinkable : Shrinkable Rat 
goal: SlimCheck.Shrinkable Rat

full_name: SlimCheck.Bool.shrinkable
code: instance Bool.shrinkable : Shrinkable Bool 
goal: SlimCheck.Shrinkable Bool

full_name: SlimCheck.Char.shrinkable
code: instance Char.shrinkable : Shrinkable Char 
goal: SlimCheck.Shrinkable Char

full_name: SlimCheck.Prod.shrinkable
code: instance Prod.shrinkable [shrA : Shrinkable α] [shrB : Shrinkable β] :
    Shrinkable (Prod α β) 
goal: SlimCheck.Shrinkable (α × β)

full_name: SlimCheck.Sigma.shrinkable
code: instance Sigma.shrinkable [shrA : Shrinkable α] [shrB : Shrinkable β] :
    Shrinkable ((_ : α) × β) 
goal: SlimCheck.Shrinkable ((_ : α) × β)

full_name: SlimCheck.List.shrinkable
code: /-- Shrink a list of a shrinkable type, either by discarding an element or shrinking an element. -/
instance List.shrinkable [Shrinkable α] : Shrinkable (List α) 
goal: SlimCheck.Shrinkable (List α)

full_name: SlimCheck.Nat.sampleableExt
code: instance Nat.sampleableExt : SampleableExt Nat 
goal: SlimCheck.SampleableExt ℕ

full_name: SlimCheck.Fin.sampleableExt
code: instance Fin.sampleableExt {n : Nat} : SampleableExt (Fin (n.succ)) 
goal: SlimCheck.SampleableExt (Fin n.succ)

full_name: SlimCheck.Int.sampleableExt
code: instance Int.sampleableExt : SampleableExt Int 
goal: SlimCheck.SampleableExt ℤ

full_name: SlimCheck.Rat.sampleableExt
code: instance Rat.sampleableExt : SampleableExt Rat 
goal: SlimCheck.SampleableExt Rat

full_name: SlimCheck.Bool.sampleableExt
code: instance Bool.sampleableExt : SampleableExt Bool 
goal: SlimCheck.SampleableExt Bool

full_name: SlimCheck.Char.sampleable
code: /-- This can be specialized into customized `SampleableExt Char` instances.
The resulting instance has `1 / length` chances of making an unrestricted choice of characters
and it otherwise chooses a character from `chars` with uniform probabilities.  -/
def Char.sampleable (length : Nat) (chars : List Char) (pos : 0 < chars.length) :
    SampleableExt Char 
goal: SlimCheck.SampleableExt Char

full_name: SlimCheck.Char.sampleableDefault
code: instance Char.sampleableDefault : SampleableExt Char 
goal: SlimCheck.SampleableExt Char

full_name: SlimCheck.Prod.sampleableExt
code: instance Prod.sampleableExt {α : Type u} {β : Type v} [SampleableExt α] [SampleableExt β] :
    SampleableExt (α × β) 
goal: SlimCheck.SampleableExt (α × β)

full_name: SlimCheck.Prop.sampleableExt
code: instance Prop.sampleableExt : SampleableExt Prop 
goal: SlimCheck.SampleableExt Prop

full_name: SlimCheck.List.sampleableExt
code: instance List.sampleableExt [SampleableExt α] : SampleableExt (List α) 
goal: SlimCheck.SampleableExt (List α)

full_name: SlimCheck.NoShrink
code: /-- An annotation for values that should never get shrinked. -/
def NoShrink (α : Type u) 
goal: Type u

full_name: SlimCheck.NoShrink.mk
code: def mk (x : α) : NoShrink α 
goal: SlimCheck.NoShrink α

full_name: SlimCheck.NoShrink.get
code: def get (x : NoShrink α) : α 
goal: α

full_name: SlimCheck.NoShrink.inhabited
code: instance inhabited [inst : Inhabited α] : Inhabited (NoShrink α) 
goal: Inhabited (SlimCheck.NoShrink α)

full_name: SlimCheck.NoShrink.repr
code: instance repr [inst : Repr α] : Repr (NoShrink α) 
goal: Repr (SlimCheck.NoShrink α)

full_name: SlimCheck.NoShrink.shrinkable
code: instance shrinkable : Shrinkable (NoShrink α) 
goal: SlimCheck.Shrinkable (SlimCheck.NoShrink α)

full_name: SlimCheck.NoShrink.sampleableExt
code: instance sampleableExt [SampleableExt α] [Repr α] : SampleableExt (NoShrink α) 
goal: SlimCheck.SampleableExt (SlimCheck.NoShrink α)

full_name: SlimCheck.printSamples
code: /--
Print (at most) 10 samples of a given type to stdout for debugging.
-/
-- Porting note: if `Control.ULiftable` is ported, make use of that here, as in mathlib3,
-- to enable sampling from higher types.
def printSamples {t : Type} [Repr t] (g : Gen t) : IO PUnit 
goal: IO PUnit.{1}

full_name: SlimCheck.mkGenerator
code: /-- Create a `Gen α` expression from the argument of `#sample` -/
def mkGenerator (e : Expr) : MetaM (Σ (u : Level) (α : Q(Type $u)), Q(Repr $α) × Q(Gen $α)) 
goal: Lean.MetaM
  ((u : Lean.Level) ×
    (α :
      let u := u;
      Q(Type u)) ×
      Q(Repr «$α») × Q(SlimCheck.Gen «$α»))

full_name: SlimCheck.«_aux_Mathlib_Testing_SlimCheck_Sampleable___elabRules_SlimCheck_command#sample__1»
code: /--
`#sample type`, where `type` has an instance of `SampleableExt`, prints ten random
values of type `type` using an increasing size parameter.

```lean
#sample Nat
-- prints
-- 0
-- 0
-- 2
-- 24
-- 64
-- 76
-- 5
-- 132
-- 8
-- 449
-- or some other sequence of numbers

#sample List Int
-- prints
-- []
-- [1, 1]
-- [-7, 9, -6]
-- [36]
-- [-500, 105, 260]
-- [-290]
-- [17, 156]
-- [-2364, -7599, 661, -2411, -3576, 5517, -3823, -968]
-- [-643]
-- [11892, 16329, -15095, -15461]
-- or whatever
```
-/
elab "#sample " e:term : command =>
  Command.runTermElabM fun _ => do
    let e ← Elab.Term.elabTermAndSynthesize e none
    let g ← mkGenerator e
    -- `printSamples` only works in `Type 0` (see the porting note)
    let ⟨0, α, _, gen⟩ := g | throwError "Cannot sample from {g.1} due to its universe"
    let printSamples := q(printSamples (t := $α) $gen)
    let code ← unsafe evalExpr (IO PUnit) q(IO PUnit) printSamples
    _ ← code
goal: Lean.Elab.Command.CommandElab

full_name: SlimCheck.«command#sample_»
code: /--
`#sample type`, where `type` has an instance of `SampleableExt`, prints ten random
values of type `type` using an increasing size parameter.

```lean
#sample Nat
-- prints
-- 0
-- 0
-- 2
-- 24
-- 64
-- 76
-- 5
-- 132
-- 8
-- 449
-- or some other sequence of numbers

#sample List Int
-- prints
-- []
-- [1, 1]
-- [-7, 9, -6]
-- [36]
-- [-500, 105, 260]
-- [-290]
-- [17, 156]
-- [-2364, -7599, 661, -2411, -3576, 5517, -3823, -968]
-- [-643]
-- [11892, 16329, -15095, -15461]
-- or whatever
```
-/
elab "#sample " e:term : command =>
  Command.runTermElabM fun _ => do
    let e ← Elab.Term.elabTermAndSynthesize e none
    let g ← mkGenerator e
    -- `printSamples` only works in `Type 0` (see the porting note)
    let ⟨0, α, _, gen⟩ := g | throwError "Cannot sample from {g.1} due to its universe"
    let printSamples := q(printSamples (t := $α) $gen)
    let code ← unsafe evalExpr (IO PUnit) q(IO PUnit) printSamples
    _ ← code
goal: Lean.ParserDescr