How abstraction and application are type-checked [Re: [Agda] Agda type inference oddity on functions]

Andreas Abel andreas.abel at ifi.lmu.de
Tue Sep 28 18:05:47 CEST 2010


I looked at the Agda type checker and want to add some clarifications  
here:

- Bidirectional type checking:  Agda does not do bidirectional  
checking (= type checking and type inference), it only does type  
checking, where checking against a metavar has similar results to type  
inference.  Still, bidirectional type checking is a metaphor that  
explains some of Agda's behavior.

As Nisse already pointed out, typed and untyped lambdas are treated  
differently.

   \ x -> t   expects to be checked against a function type.  If it  
does not get a function type (e.g., it is checked against a meta  
variable, the type checking problem is postponed, but no constraint is  
propagated that the type of \ x -> t must be a function type).
  This explains the failure of Alan's term x1.

   \ (x : A) -> t  synthesizes a function type (x : A) -> ?B where the  
new meta-var is the type of t
   @Thorsten: Thus, not all metavars come from holes in the input!

Thus, \ (x : _) and \ x behaved differently, which is unexpected and  
confusing to the outsider.  As we have seen by Alan's examples, there  
are cases where \ (x : _) works and \ x not.  Can it also be the other  
way round?

@Ulf: Could \x be treated as \(x : _) ? There seems to be some  
abandoned code "forcePi" that tried to do this...

When checking an application, it is similar to the \ x case, it  
expects the head to be a function type, postpones if this is not the  
case, but does not propagate the information that the head must be a  
function.
This explains failure of x3.

The weirdness of x5 is explained as follows.  Here, Agda needs to  
check that

   f : A <= N -> N

so again, it has the information that A {_} is a function type and can  
use that to invert on F.

So, can we improve on the type checking of an application f a?
Well if f is not yet known to be a function type, we cannot simply say  
that it should be (x : ?1) -> ?2 x, where ?1 is the type of a, because  
there might be omitted hidden arguments between f and a.  So it would be

   Delta -> (x : ?1 Delta) -> ?2 Delta x

where Delta is a telescope of hidden variables of unknown length.

Such a concept does not exist (yet) in the guts of Agda, so I guess  
the situation cannot be rectified easily.

Cheers,
Andreas


On Sep 28, 2010, at 4:06 PM, Alan Jeffrey wrote:

> On 09/28/2010 05:05 AM, Thorsten Altenkirch wrote:
>>>>> Attached is a program that defines a function whose only effect is
>>>>> to enforce that its argument is a function. The version in the  
>>>>> file
>>>>> is level-polymorphic and deals with dependent functions, but its
>>>>> simpler cousin is:
>>>>>
>>>>> isFun : {A B : Set} -> (A -> B) -> (A -> B)
>>>>> isFun f = f
>>>>>
>>>>> Then we can show that there are contexts such that:
>>>>>
>>>>> a) isFun (lambda x -> x) type-infers, but (lambda x -> x) does  
>>>>> not.
>>>>
>>>> What does "type-infers" mean?
>>>
>>> I mean "accepted by the Agda type-checker without unsolved metas",  
>>> or
>>> more concretely no yellow ink in agda-mode.
>>
>> I guessed that you mean that it successfully infers a type using C-c
>> C-d. isFun (lambda x -> x) certainly has unresolved metas.
>
> Yes, but the odd thing is we can find a context C s.t. C[lambda x ->  
> x] has unsolved metas, but C[isFun(lambda x -> x)] does not.
>
> NAD says this is due to a planned future addition to Agda -- not  
> every lambda will have function type (and ditto not every  
> application will be of a function).
>
> [...]
>
>>> In the example, they're variables, of rather weird type. The type  
>>> of f is:
>>>
>>> {b : bool} -> (F b)
>>>
>>> where:
>>>
>>> F true = (Nat -> Nat)
>>> F false = Nat
>>>
>>> So the oddness is that (isFun f x) is inferred correctly to be  
>>> (isFun
>>> (f {true}) x), but (f x) ends up as (f {Z} x) for an unsolved meta  
>>> Z.
>>> AFAICT this is because the inference algorithm doesn't infer a
>>> function type for f, even though it's been applied!
>>
>> I am rather surprised that (isFun f x) can be inferred. Can somebody
>> explain to me why this is the case.
>
> It's because F is a constructor-headed function, so the term  
> inference algorithm deduces that F is invertable.  So once there's a  
> constraint (F X == Y -> Z), this is enough to solve (X == true) and  
> hence (Y == Z == Nat).
>
> This trick is enough to code functions whose implicit arguments have  
> default value in existing Agda, if only application constrained a  
> term to be a function!
>
>> Cheers,
>> Thorsten
>
> A.
> _______________________________________________
> Agda mailing list
> Agda at lists.chalmers.se
> https://lists.chalmers.se/mailman/listinfo/agda
>

Andreas Abel  <><      Du bist der geliebte Mensch.

Theoretical Computer Science, University of Munich
Oettingenstr. 67, D-80538 Munich, GERMANY

andreas.abel at ifi.lmu.de
http://www2.tcs.ifi.lmu.de/~abel/



More information about the Agda mailing list