How abstraction and application are type-checked [Re: [Agda]
Agda type inference oddity on functions]
Alan Jeffrey
ajeffrey at bell-labs.com
Tue Sep 28 19:43:28 CEST 2010
Looks like I'm treading into dangerous water here...
On 09/28/2010 12:12 PM, Andreas Abel wrote:
> I found an example where untyped lambda succeeds but typed lambda fails:
Oh my goodness. Er, doesn't this mean there's a horrible race condition
in the unification engine? For example, swapping the order of arguments
to foo' gives:
foo'' : ({X : Set1} -> X == IdT -> X -> Set) -> Set
foo'' k = k refl (\ (x : _) -> x) -- succeeds
which looks to me that the order of constraint evaluation is making a
difference, so constraint solving isn't Church-Rosser!
A.
> module HiddenLambdaInsertion where
>
> IdT = ({A : Set} -> A -> A)
>
> data _==_ {A : Set2}(a : A) : A -> Set where
> refl : a == a
>
> foo : ({X : Set1} -> X -> X == IdT -> Set) -> Set
> foo k = k (\ x -> x) refl -- succeeds
>
> foo' : ({X : Set1} -> X -> X == IdT -> Set) -> Set
> foo' k = k (\ (x : _) -> x) refl -- fails
>
> foo succeeds because type checking \ x -> x : X is postponed first
> and can then, after X := IdT, insert a hidden lambda \ {X} before \ x.
>
> foo' fails because the type of \ (x : _) -> x is inferred as ?X -> ?X
> which cannot be unified with {A : Set} -> A -> A.
>
> So typed and untyped lambda cannot be unified into one concept unless
> we find a better heuristics of inserting hidden arguments and hidden
> abstractions.
>
> @Alan: short response below.
>
> On Sep 28, 2010, at 6:38 PM, Alan Jeffrey wrote:
>
>> Thanks for going through the typechecker Andreas!
>>
>> On 09/28/2010 11:05 AM, Andreas Abel wrote:
>> [...]
>>> 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?
>>
>> It certainly is confusing :-) I'd be surprised if there were cases
>> the other way round, as (AFAICT) \x just propogates fewer
>> constraints then \x:_ -- but then the typechecker always has
>> surprises for me!
>>
>>> @Ulf: Could \x be treated as \(x : _) ? There seems to be some
>>> abandoned code "forcePi" that tried to do this...
>>
>> This would be very nice!
>>
>> [...]
>>> 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.
>>
>> Hmm, do we really need to do this? Can we not just say that in an
>> application A B we add the typings:
>>
>> A : (x : ?1) -> (?2 x)
>> B : ?1
>>
>> This doesn't preclude A having hidden arguments, won't they get
>> resolved in the "usual fashion"? A parallel example is something
>> like (A ++ B) which adds the typings:
>>
>> A : List ?1
>> B : List ?1
>>
>> Now if later we discover that A actually has type {T} -> List U then
>> inferred arguments are added, replacing this occurrence of A, and
>> getting:
>>
>> A {?2} : List U
>> B : List U
>> ?2 : T
>
> Well, I doubt it works like this, I would rather expect to get a type
> error, because
>
> List ?1 != {T} -> List U
>
>> I must be missing something, why won't the same hidden-argument
>> resolution work for function application?
>
> Hidden Pi-abstractions are never inserted, and the inserting of hidden
> arguments and abstractions follows also a fragile heuristics.
>
>>> Such a concept does not exist (yet) in the guts of Agda, so I guess
>>> the situation cannot be rectified easily.
>>>
>>> Cheers,
>>> Andreas
>>
>> A.
>>
>>>
>>>
>>> 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/
>>>
>>
>>
>
> 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