1

I'm trying to solve the bonus exercise on page 23 of this tutorial, but I can't fill in this hole:

lem-all-filter : {A : Set}(xs : List A)(p : A -> Bool)
              -> All (satisfies p) (filter p xs)
lem-all-filter [] p = all[]
lem-all-filter (x :: xs) p with p x
... | true = {! !} :all: lem-all-filter xs p
... | false = lem-all-filter xs p

If I type C-c C-, in the hole then I get this message:

Goal: isTrue (p x)
--------------------------------
xs : List .A
p  : .A -> Bool
x  : .A
.A : Set

but I would expect the goal to have type True, since p x is true and isTrue true = True. Am I missing something?

RhubarbAndC
  • 494
  • 2
  • 13

1 Answers1

2

When you pattern match on p x, p x gets rewritten to the pattern everywhere in the context, but that hole not in the context at the time of rewriting: it appears later and hence p x in its type doesn't get rewritten. You can remember that p x is equal to true using the inspect idiom (deprecated now in favour of inspect on steroids) described later in the paper, but you can also do the following:

lem-all-filter : {A : Set}(xs : List A)(p : A -> Bool)
              -> All (satisfies p) (filter p xs)
lem-all-filter [] p = all[]
lem-all-filter (x :: xs) p with p x | λ (y : isTrue (p x)) -> y :all: lem-all-filter xs p
... | true  | onTrue = onTrue _
... | false | onTrue = lem-all-filter xs p

Here you explicitly introduce the type of the argument to :all: in the context and hence when p x gets rewritten to true, the type of onTrue reduces to True -> All (satisfies p) (x :: filter p xs) as you needed.

effectfully
  • 12,325
  • 2
  • 17
  • 40
  • Great! But why not carry on rewriting things that appear in the context later? `p x` is still true, so why forget about it? – RhubarbAndC Jul 25 '16 at 16:43
  • 1
    @RhubarbAndC, I don't know the exact reason. That equality could be added as a local `{-# REWRITE #-}` rule. But I guess it would be too expensive to track all such equalities: there can be a pretty long chain of `with`s. Also, you actually rarely need to do hacks like above. And I would consider silent implicit rewriting as confusing. – effectfully Jul 25 '16 at 16:57
  • 1
    That sounds fair enough. I'm far too much of novice at this point to know how big a difference this would make. – RhubarbAndC Jul 25 '16 at 17:01
  • Follow up question: when using the inspect idiom, why can't I pattern match on the equality proof to find that it is `refl`? The error message suggest that I need to already know that the two sides are equal, but that's silly: it should tell me that, surely? – RhubarbAndC Jul 25 '16 at 19:38
  • 1
    `RhubarbAndC`, when you pattern match on `p : x ≡ y`, Agda tries to unify `x` and `y`, but `p x` and `true` can't be unified. The solution is to generalize `p x` to a fresh variable which can be unified with `true`. See the final part of the 2.6 module of the tutorial you're reading for how this can be done. Or you can simply use [`rewrite`](http://wiki.portal.chalmers.se/agda/pmwiki.php?n=ReferenceManual.PatternMatching). – effectfully Jul 26 '16 at 03:17