[Agda] Re: Why aren't free vars in types automatically generalized

Andreas Abel andreas.abel at ifi.lmu.de
Tue Mar 31 17:29:36 CEST 2009


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Darin Morrison wrote:
> On Sun, Mar 29, 2009 at 8:04 PM, Stefan Monnier
> <monnier at iro.umontreal.ca> wrote:
>>> I agree that it is often annoying to write out all the implicit
>>> arguments in a type signature.  There are several reasons not to
>>> introduce the short-hand notation you suggest, though:
>> Were these the original reason for omitting such a feature?
>>
>>> ⑴ If something called l were to come into scope, then your program would
>>>  be broken.  Hopefully you would get a type error, but not in all cases.
>> Indeed, it's a problem.  In SML, this is solved by using a ' prefix in
>> front of the free variables.  In Twelf it is solved by requiring the
>> free vars to start with a capital letter (and it is also less
>> significant since Twelf programs seem to be (ironically) a lot more
>> "closed" (maybe I should say "self-contained") and rely a lot less on
>> libraries).
> 
> I dislike both of these "solutions".  I find it ugly to see ' all over
> the place and also find having to use capital letters is too
> restrictive, syntactically.  For example, the latter doesn't mesh well
> at all with unicode because there isn't always a clear notion of
> whether a symbol has a capital analogue.  Using capitals also prevents
> one from being able to quantify over something which should be
> interpreted as a mixfix operator (i.e., _◆_), which turns out to be
> surprisingly convenient in Agda.

I agree, these solutions are not pretty.  My suggestion is to prefix an
identifier to be bound with a special symbol, as the historic "^" from
which the lambda was derived.

  append : Vect ^A ^n -> Vect A ^m -> Vect A (n + m)

This indicates that A, n, m should be generalized.  Elaboration is just:

  append : forall {A n m} -> Vect A n -> Vect A m -> Vect A (n + m)

However, the user should not be able to rely on a particular order,
another possible elaboration is

  append : forall {n m A} -> Vect A n -> Vect A m -> Vect A (n + m)

Thus, implicit arguments can only be passed by name, e.g.,

  append {A = Bool} v w

Something like

  lemma : length (append ^v ^w) == length (append w v)

can be elaborated using Hindley-Milner-inference techniques to

  lemma : forall {bla1 bla2 bla3} ->
                 {v : Vect bla1 bla2}{w : Vect bla1 bla3} ->
                 length (append ^v ^w) == length (append w v)

bla1, bla2, bla3 are system-generated names, and consequently, the
corresponding implicit arguments cannot be passed explicitely.

   lemma {bla1 = Bool} ...

is illegal.

As far as Twelf type annotation facility is concerned:

  lemma : length (append (^v : Vect ^A ^n) v) == n + n

can be stated as

  lemma : {v : Vect ^A ^n} -> length (append v v) == n + n

which is not horribly more verbose, so I think that does not have to be
incorporated.

Andreas

>>> ⑵ What should the inferred implicit arguments be called? In your case it
>>>  is obvious, but what if l depended on something else? Note that you
>>>  can give implicit arguments by name when applying a function, so the
>>>  names matter:
>>>    f {A = …} x
>> Indeed, some arguments would not even appear, so their naming might be
>> an issue.  I know of 3 ways to reduce this problem:
>> - You don't need to give the name of explicitly provided implicit
>>  arguments.  You can pass them "positionally".
> 
> You can already do this in Agda.  Most of the time it is ugly and
> inconvenient though (not to mention hard to read) if you have a lot of
> implicit variables.
> 
>>  Or you could even
>>  imagine that Agda would just try to use explicitly provided implicit
>>  args "where they work" (i.e. look at the type of the provided argument
>>  to try and guess to which formal arg this corresponds).
> 
> Hrmm.  I could imagine this seeming a bit too mysterious and perhaps
> leading to strange typing issues elsewhere, but maybe I'm wrong.
> 
>> - Twelf uses the %name annotation to help Twelf choose a name for
>>  a variable from its type.
> 
> You can achieve something which is sort of similar by giving a name
> for an argument in the data constructor (i.e., introducing a trivial
> dependency), although this name will be specific to that constructor
> and not necessarily the type.  (Coq also does this AFAIK).  I think it
> is a bit more flexible than using %name for everything.
> 
>> - Hopefully you need to pass those implict arguments explicitly less
>>  often.  Notice, that one of the reasons why I like Twelf/HM's
>>  treatment of freevars-as-implicit-args is specifically because it
>>  reduces the need to pass implicit args explicitly, as shown in my
>>  "teLit" example:
>>
>>      teLit  : ∀{l Γ} → ℕ → TExp{l} Γ tNat
>>    =>
>>      teLit  : ℕ → TExp Γ tNat
>>
>>  Notice how I get to drop the {l} arg to TExp.  I find this situation
>>  to be one of the common cases where I need to provide implicit
>>  arguments explicitly.
> 
> Others may have a different experience, but I find that it's pretty
> rare that I need to explicitly pass implicit arguments.  Perhaps I
> have just developed an intuition about when Agda will be able to infer
> the argument and I tend not to write code where this wouldn't work, or
> maybe something else is going on.  In any case, I think it may be the
> case that there are ways to write the kind of code that you want in a
> slightly different way to where this issue doesn't occur as often.
> 
>>> ⑶ Similarly, if several independent arguments are added, in which order
>>>  should they appear in the type signature?
>> Any correct order will do.
> 
> But how will you be able to pass arguments "positionally" in this
> case?  You will need to know which order Agda has shown, which is no
> longer apparent on a purely syntactic basis.
> 
>>> This description is very vague, and I would not be surprised if I had
>>> missed some design choice or potential problem.  Has anyone worked out
>>> the details?  Would the algorithm be obvious to users of the language?
>> As mentioned, Twelf has been doing this for years, and I can't think of
>> any reason why the differences in the underlying type theory would have
>> much impact on this aspect of type reconstrution.
> 
> Just because Twelf does it that way doesn't mean that it's the best
> way or even that Agda should do it that way ;)
> 
> Just my 0.02...
> 
> (Personally, I would like to see some improvements in how implicit
> arguments are handled but I'm not convinced that the Twelf way is
> better).
> 


- --
Andreas Abel  <><      Du bist der geliebte Mensch.

Theoretical Computer Science, University of Munich
http://www.tcs.informatik.uni-muenchen.de/~abel/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFJ0jbfPMHaDxpUpLMRAij0AJ0T+hV34LahuuuInd36RqoGqdr6igCg1Gk5
Y7sI7lqq6nSrNUtevbBZ2/A=
=cedh
-----END PGP SIGNATURE-----


More information about the Agda mailing list