agda / agda

Agda is a dependently typed programming language / interactive theorem prover.

Home Page:https://wiki.portal.chalmers.se/agda/pmwiki.php

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Instance resolution failure in Agda 2.6.4

conal opened this issue · comments

I’m trying to work out how I can transition an Agda library from Agda 2.6.3 to 2.6.4, particularly the change in instance resolution (#6368). The following module shows two test cases. The first test is in the uncluttered style my library has been using and that I very much want to keep using but is no longer working as of 2.6.4:

record Foo (X : Set) : Set₁ where
  field 
    Q : X  Set
    q : {x : X}  Q x

open Foo ⦃ … ⦄

module Test (A : Set) ⦃ _ : Foo A ⦄ (B : Set) ⦃ _ : Foo B ⦄ where

  -- Resolves in 2.6.3 but not 2.6.4
  test₁ : {y : B}  Q y
  test₁ = q

  -- Resolves in 2.6.3 and 2.6.4
  test₂ : {y : B}  Q y
  test₂ {y} = q {x = y}

Is the resolution failure in test₁ intended? Can the simpler style be supported without multiple explicit openings and field/method renamings? My library is centered on homomorphic specifications (as in denotational design), so resolving two different instances of the same record/class in the same type signature is quite typical. Multiple explicit openings and field renamings would thwart the elegance of the type signatures (laws and theorems).

I think the problem here is that Agda's automatic insertion of implicit arguments is making the instance search go awry. In particular, if you make the x argument to q explicit then the example passes:

record Foo (X : Set) : Set₁ where
  field 
    Q : X  Set
    q : (x : X)  Q x

open Foo ⦃ … ⦄

module Test (A : Set) ⦃ FooA : Foo A ⦄ (B : Set) ⦃ FooB : Foo B ⦄ where

  works : (y : B)  Q y
  works = q

So the problem is that instance search does not get the task of searching for an instance inst where the type of q {{inst}} is {x : B} → Q {{inst}} x (which it could solve) but instead it it has to search for an instance inst where q {{inst}} {y} has type Q {{inst}} y. In the latter case there is no trace of the type A which it could use to choose the instance of type Foo B over the one of type Foo A.

Possible workarounds could be:

  • Making the argument {x : X} explicit.
  • Wrapping the type of q in a box that prevents Agda from eagerly inserting the implicit argument.
  • Making Q into an additional parameter of the type class (so instance search can use Q to choose the instance rather than just X.

Would any of these options be acceptable to you? The goal of this change was to make instance search more predictable and performant, but this will inevitably lead to some cases like this where Agda has a harder time choosing the correct instance.

  • Wrapping the type of q in a box that prevents Agda from eagerly inserting the implicit argument.

Would you be so kind and show what this would look like? I don't really understand this.

Thank you for the tips, @jespercockx! Of your workaround suggestions, the first and third would be terribly awkward in practice, and the second I don’t understand.

What I meant with the second point is to define a type like

data Box (A : Set) : Set where
  [_] : A -> Box A

and change the type of q from {x : X} → Q x to Box ({x : X} → Q x). But that's probably going to be pretty awkward to work with too.

If none of the workarounds here are acceptable, I'm not sure what would be the best solution here. There are just too many different use cases for instance search, and every time we make a change that makes things better (more predictable, more efficient) for one use case this inevitably makes things worse for another use case elsewhere.

(One other workaround which you probably won't like is to use tactic arguments with a custom tactic instead of instance arguments. Here is an example of a little tactic that I wrote that relies on instance search but removes the uniqueness constraint: https://github.com/jespercockx/scope/blob/master/src/Utils/Tactics.agda#L31-L55, perhaps a similar tactic could be adapted to your use case.)

Thanks again, @jespercockx! I think @jkopanski has found a strategy that we can live with. Theorems are still pretty (my top priority), and proofs are only mildly more verbose.

Ok, thanks @conal, then we do not take further action here.