Zulip Chat Archive

Stream: new members

Topic: Instances of functions


Andrew Carter (Jan 06 2023 at 00:59):

I'm trying to get some instance code working but I'm running into "maximum class-instance resolution depth has been reached ...", and I'm a little bit worried that I'm using instances beyond their intended capacity. The only instances I have defined are:

instance iteration_complexity (α: Type) [α_en: has_encoding α]
  (f: α  α) [cf: has_complexity f]: has_complexity (nat.iterate f) :=
begin
  fconstructor,
  fconstructor,
  swap,
  apply iteration_complexity_le,
  apply cf.value.2,
  refl,
  { intros a b, refl },
end

instance flip_complexity (α β γ: Type) [α_en: has_encoding α] [β_en: has_encoding β] [γ_en: has_encoding γ]
  (f: α  β  γ) [cf: has_complexity f]: has_complexity (function.swap f) :=
begin
  fconstructor,
  fconstructor,
  swap,
  apply flip_complexity_le,
  apply cf.value.2,
  refl,
  { intros a b, refl },
end

instance pred_complexity: has_complexity nat.pred :=
begin
  fconstructor,
  fconstructor,
  swap,
  apply pred_complexity_le,
end

instance sub_complexity: has_complexity nat.sub :=
begin
  rw [show nat.sub = function.swap (nat.iterate nat.pred), begin
    ext1 n, ext1 m,
    induction m generalizing n,
    { simp [nat.sub, function.swap] },
    simp only [function.swap, function.iterate_succ_apply', nat.sub, nat.sub_succ, m_ih],
  end],
  apply_instance,
  -- maximum class-instance resolution depth has been reached
  -- (the limit can be increased by setting option 'class.instance_max_depth')
  -- (the class-instance resolution trace can be visualized by setting option 'trace.class_instances')
end

The last one doesn't compile (I don't think any of the other proofs are important here, but I can provide more details if they are). With the error message in the comment. I'm wondering if this is improper use of instances because I'm matching on function names instead of types. As a human it looks pretty easy to unwrap the declaration (find an instance that matches function.swap, then find one that matches nat.iterate, then find the one for nat.pred).

Eric Wieser (Jan 06 2023 at 01:03):

I think the problem is that docs#function.swap is reducible and so flip_complexity forms a loop with itself

Andrew Carter (Jan 06 2023 at 01:10):

Ah, interesting. Wrapping a new function for flip worked, thanks @Eric Wieser .

Eric Wieser (Jan 06 2023 at 01:13):

Does docs#flip work for you?

Andrew Carter (Jan 06 2023 at 01:26):

Yes it does, not sure how I missed it, given it had the name I expected

Andrew Carter (Jan 06 2023 at 01:32):

A follow-up question (related mostly on the question of instance abuse).
I've defined the instance as follows

structure is_complexity {α: Type} [has_encodable_function α] (f: α):=
mk :: (cost : cost_function' α) (inv : complexity_le f cost)

class has_complexity {α: Type} [has_encodable_function α] (f: α) :=
  (value: is_complexity f)

def complexity {α: Type} [has_encodable_function α]  (f: α) [cf: has_complexity f] :=
  cf.value.1

is there a way for me to interact with the underlying cost function from an instance? Or is it quotiented away in some sense.
I.e.

def sc_cost:      := λ n m, (2 * n + 15) * m + 5
theorem sc: (complexity nat.sub).always_le sc_cost :=
begin
  intros n m,
  simp [complexity, sc_cost],
  -- |- has_complexity.value.cost n m ≤ (2 * n + 15) * m + 5
  sorry,
end

Reid Barton (Jan 06 2023 at 08:08):

Sure it's possible, though it will be kind of hard to work with because you used rw to define data

Reid Barton (Jan 06 2023 at 08:09):

It would be better to define a function like docs#fin.cast that copies the data, and only rewrites in the proof

Andrew Carter (Jan 09 2023 at 23:19):

Thanks, I'll take a look


Last updated: Dec 20 2023 at 11:08 UTC