Phantom arguments in functions [Re: [Agda] another possible
without-K problem]
Andreas Abel
andreas.abel at ifi.lmu.de
Thu Jul 11 01:05:33 CEST 2013
Dan, Guillaume,
Here is a revised showcase for the phantom trick, following your
improvement suggestions.
* There is not need for a Phantom record type, one can just take a
parametrized unit type.
* The phantom argument can be found by instance search.
Of course, one can define a wrapper that supplies the phantom
argument, like Dan did below.
Hmm, since people need to work around the unused argument analysis, I
wonder whether it was good to add it. I wanted definitional equality to
be a bit more "extensional". But it seems the workaround is only needed
in another workaround (the absence of HITs). ;-)
Cheers, Andreas
import Common.Level
open import Common.Equality
data Phantom {A : Set}(a : A) : Set where
phantom : Phantom a
postulate
A : Set
a : A
Unused : Set
u1 u2 : Unused
data Unit : Set where
unit : Unit
bla : (u : Unused) → Unit → A
bla u unit = a
same : {x : Unit} → bla u1 x ≡ bla u2 x
same = refl
fool : (u : Unused){{z : Phantom u}} → Unit → A
fool u {{phantom}} unit = a
same? : ∀ {x : Unit} → fool u1 x ≡ fool u2 x
same? = refl
-- ERROR:
-- u1 != u2 of type Unused
-- when checking that the expression refl has type
-- fool u1 .x ≡ fool u2 .x
On 10.07.13 9:09 PM, Dan Licata wrote:
> Hi Andreas, Guillaume,
>
> Andreas, thanks for the suggestion!
>
> Guillaume, unless I'm mistaken, or things have changed since 2.3.2.1, I think there
> is a simpler way to avoid the annoyance of the phantom argument:
>
> - To make an unused argument used, you need to match on a "phantom"
> argument indexed by that argument. (I.e. it's important that
> the unit in Andreas's code is a data, not a record)
>
> - But it's OK if the function is always called on the canonical
> inhabitant of the type you're matching on---you don't need to quantify
> over variable phantoms like Andreas is doing in his example.
Yes, of course, that is simpler & better.
> This is important for getting the right definitional behavior, as
> otherwise the match on the phantom would block reduction.
>
> So the trick can be hidden in the implementation of the HIT, without
> changing the external interface.
>
> For example, the following implementation of a higher inductive type
> works for me in 2.3.2.1. (Guillaume, does it still work in the
> development version?)
>
> Andreas, perhaps you could confirm that this is reasonable, given the
> meaning of the unused argument check?
Yes, this is reasonable.
> Also: does anyone know if there is a nice way to install and switch between multiple versions of Agda?
> How would I have 2.3.2.1 from cabal and the devel version installed
> simultaneously?
>
> -Dan
>
> ----------------------------------------------------------------------
>
> {-# OPTIONS --type-in-type --without-K #-}
>
> open import lib.Prelude -- ≃ and id are the identity type and refl; Type is Set
>
> module misc.Phantom where
>
> data Unit⁺ : Type where
> <>⁺ : Unit⁺
>
> record Phantom {A : Type}(a : A) : Type where
> constructor phantom
> field
> match : Unit⁺
>
> module S where
> private
> data S¹' : Type where
> Base : S¹'
>
> S¹ : Type
> S¹ = S¹'
>
> base : S¹
> base = Base
>
> postulate {- HoTT Axiom -}
> loop : Path base base
>
> S¹-rec' : {C : Type}
> -> (c : C)
> -> (p : c ≃ C) (_ : Phantom p)
> -> S¹ -> C
> S¹-rec' c p (Phantom.phantom <>⁺) Base = c
>
> S¹-rec : {C : Type}
> -> (c : C)
> -> (p : c ≃ c)
> -> S¹ -> C
> S¹-rec c p = S¹-rec' c p (Phantom.phantom <>⁺)
>
> {- correctly fails:
>
> p != q of type Id c c
> when checking that the expression id has type
> Id (S.rec c p) (S.rec c q)
>
> test : {C : Type}
> -> (c : C)
> -> (p q : c ≃ c)
> → S.S¹-rec c p ≃ S.S¹-rec c q
> test c p q = id
> -}
>
> -- still get definitional computation on points
>
> test' : {C : Type}
> -> (c : C)
> -> (p : c ≃ c)
> → S.S¹-rec c p S.base ≃ c
> test' c p = id
>
>
>
> On Jul10, Guillaume Brunerie wrote:
>> Thanks for the workaround!
>> It’s not optimal though, you have to give the silly [z] argument
>> everytime you use [fool] which is a bit annoying.
>> But this is easy to fix by making the argument [z] of [fool] an
>> instance argument instead of an implicit argument and by putting
>> somewhere in the context the following definition:
>>
>> inhab-Phantom : {A : Set} {a : A} -> Phantom a Unit
>> inhab-Phantom = phantom unit
>>
>> Then you can use [fool] just as you use [bla]:
>>
>> same? : {x : Unit} → fool u1 x ≡ fool u2 x
>> same? = refl
>>
>> gives the expected error.
>>
>> Guillaume
>>
>> 2013/7/10 Andreas Abel <andreas.abel at ifi.lmu.de>:
>>> On 10.07.2013 16:54, Dan Licata wrote:
>>>>
>>>> Also, related to implementing higher inductives, but not to without-K:
>>>> is there a way to turn off/defeat the unused arguments analysis that is
>>>> new in 2.3.2.1? It breaks some of the things I'm doing: I want a
>>>> function with a "phantom" parameter, where different values of the
>>>> phantom parameter do not automatically get equated.
>>>
>>>
>>> Data and record types still have phantom arguments, which can be exploited.
>>>
>>> Would this workaround help you?
>>>
>>> import Common.Level
>>> open import Common.Equality
>>>
>>> record Phantom {A : Set}(a : A)(B : Set) : Set where
>>> constructor phantom
>>> field
>>> thePhantom : B
>>> open Phantom
>>>
>>> postulate
>>> A : Set
>>> a : A
>>> Unused : Set
>>> u1 u2 : Unused
>>>
>>> data Unit : Set where
>>> unit : Unit
>>>
>>> bla : (u : Unused) → Unit → A
>>> bla u unit = a
>>>
>>> same : {x : Unit} → bla u1 x ≡ bla u2 x
>>> same = refl
>>>
>>> fool : (u : Unused){z : Phantom u Unit} → Unit → A
>>> fool u {phantom unit} unit = a
>>>
>>> same? : ∀ {x : Unit}{y z} → fool u1 {y} x ≡ fool u2 {z} x
>>> same? = refl
>>>
>>> -- ERROR:
>>> -- u1 != u2 of type Unused
>>> -- when checking that the expression refl has type
>>> -- fool u1 .x ≡ fool u2 .x
>>>
>>>
--
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