Search code examples
idrisdependent-type

Proving equality of types depending on (further) proofs


Suppose we'd like to have a "proper" minus on Nats, requiring m <= n for n `minus` m to make sense:

%hide minus

minus : (n, m : Nat) -> { auto prf : m `LTE` n } -> Nat
minus { prf = LTEZero } n Z = n
minus { prf = LTESucc prevPrf } (S n) (S m) = minus n m

Now let's try to prove the following lemma, stating that (n + (1 + m)) - k = ((1 + n) + m) - k, assuming both sides are valid:

minusPlusTossS : (n, m, k : Nat) ->
                 { auto prf1 : k `LTE` n + S m } ->
                 { auto prf2 : k `LTE` S n + m } ->
                 minus (n + S m) k = minus (S n + m) k

The goal suggests the following sublemma might help:

plusTossS : (n, m : Nat) -> n + S m = S n + m
plusTossS Z m = Refl
plusTossS (S n) m = cong $ plusTossS n m

so we try to use it:

minusPlusTossS n m k =
  let tossPrf = plusTossS n m
  in rewrite tossPrf in ?rhs

And here we fail:

When checking right hand side of minusPlusTossS with expected type
        minus (n + S m) k = minus (S n + m) k

When checking argument prf to function Main.minus:
        Type mismatch between
                LTE k (S n + m) (Type of prf2)
        and
                LTE k replaced (Expected type)

        Specifically:
                Type mismatch between
                        S (plus n m)
                and
                        replaced

If I understand this error correctly, it just means that it tries to rewrite the RHS of the target equality (which is minus { prf = prf2 } (S n + m) k) to minus { prf = prf2 } (n + S m) k and fails. Rightfully, of course, since prf is a proof for a different inequality! And while replace could be used to produce a proof of (S n + m) k (or prf1 would do as well), it does not look like it's possible to simultaneously rewrite and change the proof object so that it matches the rewrite.

How do I work around this? Or, more generally, how do I prove this lemma?


Solution

  • Ok, I guess I solved it. Bottom line: if you don't know what to do, do a lemma!

    So we have a proof of two minuends n1, n2 being equal, and we need to produce a proof of n1 `minus` m = n2 `minus` m. Let's write this down!

    minusReflLeft : { n1, n2, m : Nat } -> (prf : n1 = n2) -> (prf_n1 : m `LTE` n1) -> (prf_n2 : m `LTE` n2) -> n1 `minus` m = n2 `minus` m
    minusReflLeft Refl LTEZero LTEZero = Refl
    minusReflLeft Refl (LTESucc prev1) (LTESucc prev2) = minusReflLeft Refl prev1 prev2
    

    I don't even need plusTossS anymore, which can be replaced by a more directly applicable lemma:

    plusRightS : (n, m : Nat) -> n + S m = S (n + m)
    plusRightS Z m = Refl
    plusRightS (S n) m = cong $ plusRightS n m
    

    After that, the original one becomes trivial:

    minusPlusTossS : (n, m, k : Nat) ->
                     { auto prf1 : k `LTE` n + S m } ->
                     { auto prf2 : k `LTE` S n + m } ->
                     minus (n + S m) k = minus (S n + m) k
    minusPlusTossS {prf1} {prf2} n m k = minusReflLeft (plusRightS n m) prf1 prf2