[Agda] Pie in the sky

Alan Jeffrey ajeffrey at bell-labs.com
Sun Sep 26 04:29:50 CEST 2010


On 09/25/2010 12:22 AM, Samuel Gélineau wrote:
> On 2010-09-24 at 9:44 PM, Alan Jeffrey wrote:
>> Yes, but the default is provided by the *type* of f, not by the name of f,
>> so when the type inference system deduces the type of f, this will cause new
>> implicit arguments to be filled in, which may cause further type inference.
>
> My understanding was that the signature was a nice place to write the
> defaults, but that adding them should in no way change the function's
> type. If f and g both have the same signature except for their choice
> of default, do you really want them to have distinct types? If f has
> type ((x y : T) ->   {x==y ? refl : x == y} ->   U) and foo asks for a
> value of type ((x y : T) ->   {_ : x == y} ->   U), do you really want
> (foo f) not to type-check?

Let's say you put the default argument into the function itself, rather 
than the function's type, something like:

   lambda {x ? M : T} -> N  with type  {x : T} -> U

then eta-beta-equivalence gives:

   lambda {x ? M : T} -> N
     =eta= lambda {x : T} -> ((lambda {x ? M : T} -> N) x)
     =beta= lambda {x : T} -> N

and oh dear, the default has disappeared.  Eta-beta on functions is so 
hard-wired into dependent type theory that I'd be worried about messing 
with it.

And yes, you'd need (foo f) in your example not to typecheck.  Let's say 
foo = lambda g -> M -- this gets its implicit parameters resolved at 
compile time, say to give lambda g -> M'.  But M[f/g] would resolve the 
implicit parameters differently, so we'd have foo f having different 
semantics than M[f/g], thus breaking beta-equivalence.

> If you do insist on defaults being part of the type, then I have an
> alternate proposal for you.

Hmm, that's interesting -- a type (? d : A), I hadn't thought of it that 
way round.  I'm not sure how it would interact with the constraint 
satisfaction algorithm for type inference -- when given a constraint X : 
(? Y : Z), at what point do you transform this to the constraints X = Y, 
X : Z?

If the primitive is {x ? M : T} -> U, then the point that M is 
introduced is the point at which the constraint satisfaction algorithm 
decides that an implicit argument needs to be introduced.  (Which it 
must be said is slightly mysterious to me, and indeed I've caught the 
type inference system being rather opportunistic about introducing 
implicit arguments before.)

> If the types A and (? d : A) really are different, there should be a
> mechanism to extract a value of type A from a value v of type (? d :
> A). Call this mechanism (val v). There should also be a mechanism to
> convert a value of type A into a value of type (? d : A), for those
> times when d does not have the right type and you need to pass in a
> value x of type A explicitly. Call this mechanism (explicit x). And
> while we're at it, let's throw in (implicit p), for those times when
> the value p proves that the default value d does have the correct
> type.
>
> My proposal is to add two new builtins, (_﹖_∶_) and val, defined as follows.
>
>
> infix 0 _﹖_∶_
> data _﹖_∶_ (CommonA : Set) (default : CommonA) (A : Set) : Set where
>    explicit : A → CommonA ﹖ default ∶ A
>    implicit : CommonA ≡ A → CommonA ﹖ default ∶ A
>
> val : ∀ {CommonA default A} → CommonA ﹖ default ∶ A → A
> val (explicit a) = a
> val .{A} {default} {A} (implicit refl) = default
>
>
> Whenever Agda infers that an omitted parameter x has type (CommonA ﹖
> default ∶ A), it would try {x = implicit refl} instead of {x = _}. The
> solves a meta without introducing new ones, so it shouldn't affect
> termination. Using the new builtins would look as follows.
>
>
> f : (x y : ℕ) → {x≡y : x ≡ x ﹖ refl ∶ x ≡ y} → suc x ≡ suc y
> f x y {x≡y} with val x≡y
> f x .x {_} | refl = refl
>
> foo : suc (2 + 3) ≡ suc (1 + 4)
> foo = f (2 + 3) (1 + 4)
>
> bar : ∀ x y → x ≡ y → suc x ≡ suc y
> bar x y p = f x y {explicit p}
>
>
>> Could be.  I'm still worried about nontermination.  Of course, we still know
>> soundness, because type checking is terminating, and pragmatically there's
>> not much difference between nontermination and trying to typecheck a model
>> of category theory :-)
>
> I find it funny that we're working in a language where every function
> has to pass a termination checker, yet each language extension gets
> scrutinized to make sure they are terminating. Somebody should write a
> provably-terminating Agda compiler in Agda; this would make it much
> easier to ensure that further language extensions preserve
> termination.
>
> – Samuel

A.



More information about the Agda mailing list