doc: elabissues from reid visit
This commit is contained in:
parent
4794902f42
commit
5ce34b0b3c
3 changed files with 141 additions and 0 deletions
40
tests/elabissues/typeclasses_with_emetavariables.lean
Normal file
40
tests/elabissues/typeclasses_with_emetavariables.lean
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/-
|
||||
The current plan is to allow typeclass resolution to be triggered when there are still
|
||||
expression metavariables in the goal.
|
||||
|
||||
It will return:
|
||||
|
||||
success: it succeeded without needing to unify a regular metavar with anything
|
||||
fail: it failed without even getting a chance to unify a regular metavar with anything
|
||||
wait: it would have needed to unify a regular metavar with something
|
||||
|
||||
If it returns `wait`, the elaborator may try again later after learning more about the goal.
|
||||
|
||||
Note: this only applies to expression metavariables.
|
||||
See typeclasses_with_umetavariables.lean for a discussion of universe metavariables.
|
||||
-/
|
||||
|
||||
class Foo (b : Bool)
|
||||
class Bar (b : Bool)
|
||||
class Rig (b : Bool)
|
||||
|
||||
@[instance] axiom FooTrue : Foo true
|
||||
@[instance] axiom FooToBar (b : Bool) : HasCoe (Foo b) (Bar b)
|
||||
|
||||
/- [success] In the following example, `Foo.mk _ : Foo ?m₁` would coerce to `Bar ?m₁`,
|
||||
since resolution would succeed without ever needing to unify `?m₁`. -/
|
||||
noncomputable def tcSuccess :=
|
||||
[Bar.mk _, Foo.mk _, Bar.mk true]
|
||||
|
||||
/- [failure] In this example, since there is no coercion from `Foo` to `Rig`,
|
||||
resolution would fail immediately without bothering to wait.-/
|
||||
noncomputable def tcFail :=
|
||||
[Rig.mk _, Foo.mk _]
|
||||
|
||||
|
||||
@[instance] axiom FooToRig : HasCoe (Foo true) (Rig true)
|
||||
|
||||
/- [wait] In this example, the coercion from `Foo.mk _ : Foo ?m₁` to `Rig ?m₁`
|
||||
would wait, but then be queried again later and succeed.-/
|
||||
noncomputable def tcWait :=
|
||||
[Rig.mk _, Foo.mk _, Rig.mk true]
|
||||
60
tests/elabissues/typeclasses_with_preconditions.lean
Normal file
60
tests/elabissues/typeclasses_with_preconditions.lean
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/-
|
||||
The current plan is to allow instances to have preconditions with registered tactics.
|
||||
Typeclass resolution will delay these proof obligations, effectively assuming that they will succeed.
|
||||
If typeclass resolution succeeds, it will return a list of (mvar, lctx) pairs to the elaborator,
|
||||
which will try to synthesize the proofs and throw a good error message if it fails.
|
||||
-/
|
||||
|
||||
class Foo (b : Bool) : Type
|
||||
|
||||
class FooTrue (b : Bool) extends Foo b : Type :=
|
||||
(H : b = true)
|
||||
|
||||
/- This requires the tactic framework and auto_param. -/
|
||||
-- @[instance] axiom CoeFooFooTrue (b : Bool) (H : b = true . refl) : HasCoe (Foo b) (FooTrue b)
|
||||
|
||||
instance BoolToFoo (b : Bool) : Foo b := Foo.mk b
|
||||
|
||||
def forceFooTrue (b : Bool) (fooTrue : FooTrue b) : Bool := b
|
||||
|
||||
/- Should succeed (once CoeFooFooTrue can be written) -/
|
||||
#check forceFooTrue true (Foo.mk true)
|
||||
|
||||
/- Should fail (even after CoeFooFooTrue can be written -/
|
||||
#check forceFooTrue false (Foo.mk false)
|
||||
|
||||
/-
|
||||
This plan has one limitation, that has so far been deemed acceptable:
|
||||
it will not support classes with different instances depending on the provability of preconditions.
|
||||
The classic example is multiplying two elements of `ℤ/nℤ` where `n` is not prime.
|
||||
Here is a toy version of this problem:
|
||||
|
||||
<<
|
||||
@[class] axiom Prime (p : Nat) : Prop
|
||||
|
||||
@[instance] axiom p2 : Prime 2
|
||||
@[instance] axiom p3 : Prime 3
|
||||
|
||||
@[class] axiom Field : Type → Type
|
||||
@[class] axiom Ring : Type → Type
|
||||
|
||||
@[instance] axiom FieldToHasDiv (α : Type) [Field α] : HasDiv α
|
||||
@[instance] axiom FieldToHasMul (α : Type) [Field α] : HasMul α
|
||||
@[instance] axiom RingToHasMul (α : Type) [Ring α] : HasMul α
|
||||
|
||||
axiom mkType : Nat → Type
|
||||
|
||||
@[instance] axiom PrimeField (n : Nat) (Hp : Prime n . provePrimality) : Field (mkType n)
|
||||
@[instance] axiom NonPrimeRing (n : Nat) : Ring (mkType n)
|
||||
|
||||
example (α β : mkType 4) : α * β = β * α
|
||||
>>
|
||||
|
||||
The issue is that (depending on the order the instances are tried),
|
||||
the instance involving `FieldToHasMul` will succeed in typeclass resolution,
|
||||
but the proof will fail later on.
|
||||
|
||||
I (@dselsam) still thinks this plan is a good compromise.
|
||||
For examples like this, the definition in question (i.e. `Prime`) can be made a class instead
|
||||
and taken as an inst-implicit argument to `PrimeField`.
|
||||
-/
|
||||
41
tests/elabissues/typeclasses_with_umetavariables.lean
Normal file
41
tests/elabissues/typeclasses_with_umetavariables.lean
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/-
|
||||
In constrast to expression metavariables (see: typeclasses_with_emetavariables.lean),
|
||||
typeclass resolution is not stalled due to the presence of universe metavariables.
|
||||
|
||||
In the current C++ implementation, some (but not all) universe metavariables appearing
|
||||
in typeclass goals are converted to temporary metavariables.
|
||||
-/
|
||||
|
||||
class Foo.{u, v} (α : Type.{u}) : Type.{v}
|
||||
class Bar.{u} (α : Type) : Type.{u}
|
||||
|
||||
@[instance] axiom foo5 : Foo.{0, 5} Unit
|
||||
|
||||
def synthFoo {X : Type} [inst : Foo X] : Foo X := inst
|
||||
|
||||
set_option trace.class_instances true
|
||||
set_option pp.all true
|
||||
|
||||
/-
|
||||
Currently, universe variables in the level params of the *outer-most head symbol*
|
||||
of the class are converted to temporary metavariables.-/
|
||||
noncomputable def f1 : Foo Unit := synthFoo
|
||||
|
||||
def synthFooBar.{u, v} {X : Type*} [inst : Foo.{u, v} (Bar.{u} X)] : Foo.{u, v} (Bar.{u} X) := inst
|
||||
@[instance] axiom fooBar5.{u} : Foo.{5, u} (Bar.{5} Unit)
|
||||
|
||||
/-
|
||||
This *nested* universe parameter is not converted into a temporary metavariable, and so this fails.-/
|
||||
noncomputable def f2 : Foo (Bar Unit) := synthFooBar
|
||||
|
||||
/-
|
||||
Here is the trace:
|
||||
<<
|
||||
[class_instances] (0) ?x_0 : Foo.{?u_0 ?u_1} (Bar.{?l__fresh.4.77} Unit) := fooBar5.{?u_2}
|
||||
failed is_def_eq
|
||||
[class_instances] (0) ?x_0 : Foo.{?u_0 ?u_1} (Bar.{?l__fresh.4.77} Unit) := foo5
|
||||
failed is_def_eq
|
||||
>>
|
||||
|
||||
Note that the universe metavariable in question is converted to a temporary metavariable in only one of the two occurrences.
|
||||
-/
|
||||
Loading…
Add table
Reference in a new issue