[Agda] Recursive instance search
Ulf Norell
ulf.norell at gmail.com
Sun Jul 13 17:47:44 CEST 2014
It's very nice! Also much faster than the previous implementation, I have
examples that uses a lot of instance arguments that run 5x faster now, not
to mention that you can leave out all the silly specialisations like Eq
(List Nat).
I had to do a bit of work to get constructor classes (like Monad and
Functor) to work:
I lifted the restriction on recursive instances when there are metas in the
goal. The reason for this is that you get instance constraints like Monad
_M, with a side constraint _M Nat == IO Nat. To avoid the looping behaviour
you described in the release notes I prevent instance search from
instantiating insufficiently constrained metas, but allow it to instantiate
_M in the example above.
Unless someone has found any big issues, I want to merge this into master.
/ Ulf
On Fri, Jul 11, 2014 at 7:32 PM, Ulf Norell <ulf.norell at gmail.com> wrote:
> Awesome work. For now, I put it in a branch 'classes' in the main repo and
> granted you commit rights. I will try it out on UlfNorell/agda-prelude,
> which uses a lot of instance arguments.
>
> / Ulf
>
>
> On Fri, Jul 11, 2014 at 12:26 PM, Guillaume Brunerie <
> guillaume.brunerie at gmail.com> wrote:
>
>> Hello all,
>>
>> As some of you know, I started working on recursive instance search
>> during the previous AIM and the code is now available on my GitHub
>> here : https://github.com/guillaumebrunerie/agda (should I open a pull
>> request against the official Agda?)
>>
>> The main outstanding issue is that there is no termination check yet
>> so if you’re not careful when defining your instances you can easily
>> make Agda loop.
>> Also, I haven’t really thought about namespace management, for
>> instance 'hiding' does not hide instances (but serialization should
>> work, though).
>>
>> I copy-pasted the relevant part of the CHANGELOG below (I borrowed
>> part of the text in issue 938) and you can also look at the two files
>> test/succeed/RecursiveInstanceSearch{,Level}.agda to see some more
>> advanced examples of recursive instance search.
>>
>> Of course I welcome any feedback/bug reports.
>>
>> Cheers,
>> Guillaume
>>
>>
>>
>>
>> * Instance search is now more efficient and recursive (see issue 938)
>> (but without termination check yet)
>>
>> A new keyword `instance' has been introduced (in the style of
>> `abstract' and `private') which must now be used for every
>> definition/postulate that has to be taken into account during instance
>> resolution. For example:
>>
>> {-# OPTIONS --copatterns #-}
>>
>> record RawMonoid (A : Set) : Set where
>> field
>> nil : A
>> _++_ : A -> A -> A
>> open RawMonoid
>>
>> instance
>> rawMonoidList : {A : Set} -> RawMonoid (List A)
>> rawMonoidList = record { nil = []; _++_ = List._++_ }
>>
>> -- using copatterns to define this recursive instance:
>>
>> rawMonoidMaybe : {A : Set} {{m : RawMonoid A}} -> RawMonoid (Maybe
>> A)
>> nil rawMonoidMaybe = nothing
>> _++_ rawMonoidMaybe nothing mb = mb
>> _++_ rawMonoidMaybe ma nothing = ma
>> _++_ (rawMonoidMaybe {{m}}) (just a) (just b) = just (_++_ m a b)
>>
>> Moreover, each type of an instance must end in (something that reduces
>> to) a named type (e.g. a record, a datatype or a postulate). This
>> allows us to build a simple index structure
>>
>> data/record name --> possible instances
>>
>> that speeds up instance search.
>>
>> Instance search takes into account all local bindings and all global
>> 'instance' bindings and the search is recursive. For instance,
>> searching for
>>
>> ? : RawMonoid (Maybe (List A))
>>
>> will consider the candidates {rawMonoidList, rawMonoidMaybe}, fail to
>> unify the first one, succeeding with the second one
>>
>> ? = rawMonoidMaybe {A = List A} {{m = ?m}} : RawMonoid (Maybe (List
>> A))
>>
>> and continue with goal
>>
>> ?m : RawMonoid (List A)
>>
>> This will then find
>>
>> ?m = rawMonoidList {A = A}
>>
>> and putting together we have the solution.
>>
>> Be careful that there is no termination check for now, you can easily
>> make Agda loop by declaring the identity function as an instance. But
>> it shouldn’t be possible to make Agda loop by only declaring
>> structurally recursive instances (whatever that means).
>>
>> Additionally:
>>
>> * Uniqueness of instances is up to definitional equality (see issue 899)
>>
>> * Instance search will not be attempted if there are unsolved metas in
>> the goal. The issue is that trying to typecheck [? ++ ?] would
>> generate a constraint of type `RawMonoid ?' to be solved by instance
>> search, but unification with `rawMonoidMaybe' will succeed and
>> generate a new constraint of type `RawMonoid ?2' to be solved by
>> instance search, and so on, so Agda would loop.
>>
>> As a special case, if none of the instances declared for that type
>> is recursive, then instance search is attempted as usual even if
>> there are unsolved metas (no risk of looping here).
>>
>> * Instances of the following form are allowed:
>>
>> Π-level : {n : ℕ} {A : Set} {B : A → Set}
>> {{_ : (a : A) → has-level n (B a)}}
>> → has-level n ((a : A) → B a)
>>
>> When searching recursively for an instance of type `(a : A) →
>> has-level n (B a)', a lambda will automatically be introduced and
>> instance search will search for something of type `has-level n (B
>> a)' in the context extended by `a : A'.
>>
>> * There is no longer any attempt to solve irrelevant metas by instance
>> search
>>
>> * Constructors of records and datatypes are automatically added to the
>> instance table
>> _______________________________________________
>> Agda mailing list
>> Agda at lists.chalmers.se
>> https://lists.chalmers.se/mailman/listinfo/agda
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.chalmers.se/pipermail/agda/attachments/20140713/7ba0dd42/attachment.html
More information about the Agda
mailing list