0

I'm trying to implement Agda's inspect idiom in Idris, as a possible workaround for this problem, however, it seems when I pattern match on the MkReveal constructor, the choice of f is lost and instead becomes a free parameter.

First, the Idris port of inspect:

%default total

data Reveal : {a : Type} -> {b : a -> Type} -> (f : (x : a) -> b x) -> (x : a) -> (y : b x) -> Type where
  MkReveal : {a : Type} -> {b : a -> Type} -> {f : (x : a) -> b x} -> {x : a} -> {y : b x} -> (f x = y) -> Reveal {b = b} f x y

inspect : {b : a -> Type} -> (f : (x : a) -> b x) -> (x : a) -> Reveal f x (f x)
inspect {b = b} f x = MkReveal {b = b} {f = f} {y = f x} Refl

applyInspect : {b : a -> Type} -> (f : (x : a) -> b x) -> (x : a) -> (y ** Reveal f x y)
applyInspect f x = (f x ** inspect f x)

Then how I try to use it:



foo : (Monad m) => m ()
foo = do
    let selected = the (Vect 2 Nat) $ pure 0
    let elems = the (Vect 9 Nat) $ pure 0

    let (((n ** xs), (k ** ys)) ** MkReveal eq) = 
            applyInspect (partition (`elem` selected)) elems
    ?wtf

Here, in the hole ?wtf I would expect the type of eq to be partition (`elem` selected) elems = ((n ** xs), (k ** ys)). However, instead, a new implicitly-bound variable f is brought in scope:

f : (x : Vect (fromInteger 9) Nat) ->
    (\__pi_arg4 => ((p : Nat ** Vect p Nat), (q : Nat ** Vect q Nat))) x
eq : f elems = ((n ** xs), (k ** ys))

Edited to add: I have discovered that if I manually specify the b agument to applyInspect, I can get the desired type for eq:

    let (((n ** xs), (k ** ys)) ** MkReveal eq) = 
            applyInspect {b = \_ => (DPair Nat (\p => Vect p Nat), DPair Nat (\q => Vect q Nat))}
                (partition (`elem` selected)) elems

This results in

eq : partition (\ARG =>
                  elemBy (\meth, meth =>
                            Prelude.Nat.Nat implementation of Prelude.Interfaces.Eq, method == meth
                                                                                               meth)
                         ARG
                         selected)
               elems =
     ((n ** xs), (k ** ys))

which is what I'd want.

So, maybe a related question could be, how was I supposed to figure this out (there are no yellow highlights like one you'd get in Agda for unsolved metas...), and is there a way to tweak Reveal or applyInspect's definitions so that the b argument is correctly inferred?

Cactus
  • 27,075
  • 9
  • 69
  • 149
  • FWIW, changing `inspect`/`applyInspect` to only support non-dependent `f` (i.e. changing the type of `f` to `a -> b`) doesn't change anything. – Cactus May 21 '20 at 07:56

1 Answers1

1

Turns out the root of this problem is overloading: without knowing its specific type, the occurrence of partition is ambiguous between Prelude.List.partition and Data.Vect.partition.

Changing the code to

let (((n ** xs), (k ** ys)) ** MkReveal eq) = 
        applyInspect (Data.Vect.partition (`elem` selected)) elems

assigns the correct type to eq.

Also, it turns out the whole Reveal machinery isn't giving much, i.e. I can do everything with the simpler

inspect : {b : a -> Type} -> (f : (x : a) -> b x) -> (x : a) -> (y ** (f x = y))
inspect f x = (f x ** Refl)
Cactus
  • 27,075
  • 9
  • 69
  • 149