using rewrite in Refl

2019-07-18 02:42发布

问题:

I am working through Chapter 8 Type Driven Development with Idris, and I have a question about how rewrite interacts with Refl.

This code is shown as an example of how rewrite works on an expression:

myReverse : Vect n elem -> Vect n elem
myReverse [] = []
myReverse {n = S k} (x :: xs)
    = let result = myReverse xs ++ [x] in
          rewrite plusCommutative 1 k in result

where plusCommutative 1 k will look for any instances of 1 + k and replace it with k + 1.

My question is with this solution to rewriting plusCommutative as part of the exercies as myPlusCommutes with an answer being:

myPlusCommutes : (n : Nat) -> (m : Nat) -> n + m = m + n
myPlusCommutes Z m = rewrite plusZeroRightNeutral m in Refl
myPlusCommutes (S k) m = rewrite myPlusCommutes k m in
                         rewrite plusSuccRightSucc m k in Refl

I am having trouble with this line:

myPlusCommutes Z m = rewrite plusZeroRightNeutral m in Refl

because from what I can understand by using Refl on its own in that line as such:

myPlusCommutes Z m = Refl

I get this error:

When checking right hand side of myPlusCommutes with expected type
        0 + m = m + 0

Type mismatch between
        plus m 0 = plus m 0 (Type of Refl)
and
        m = plus m 0 (Expected type)

Specifically:
        Type mismatch between
                plus m 0
        and
                m

First off, one thing I did not realize is that it appears Refl works from the right side of the = and seeks reflection from that direction.

Next, it would seem that rewriting Refl results in a change from plus m 0 = plus m 0 to m = plus m 0, rewriting from the left but stopping after the first replacement and not going to so far as to replace all instances of plus m 0 with m as I would have expected.

Ultimately, that is my question, why rewriting behaves in such a way. Is rewriting on equality types different and in those cases rewrite only replaces on the left side of the =?

回答1:

To understand what is going on here we need to take into account the fact that Refl is polymorphic:

λΠ> :set showimplicits
λΠ> :t Refl
Refl : {A : Type} -> {x : A} -> (=) {A = A} {B = A} x x

That means Idris is trying to ascribe a type to the term Refl using information from the context. E.g. Refl in myPlusCommutes Z m = Refl has type plus m 0 = plus m 0. Idris could have picked the LHS of myPlusCommutes' output type and tried to ascribe the type m = m to Refl. Also you can specify the x expression like so : Refl {x = m}.

Now, rewrite works with respect to your current goal, i.e. rewrite Eq replaces all the occurrences of the LHS of Eq with its RHS in your goal, not in some possible typing of Refl.

Let me give you a silly example of using a sequence of rewrites to illustrate what I mean:

foo : (n : Nat) -> n = (n + Z) + Z
foo n =
  rewrite sym $ plusAssociative n Z Z in   -- 1
  rewrite plusZeroRightNeutral n in        -- 2 
  Refl                                     -- 3
  • We start with goal n = (n + Z) + Z, then
  • line 1 turns the goal into n = n + (Z + Z) using the law of associativity, then
  • line 2 turns the current goal n = n + Z (which is definitionally equal to n = n + (Z + Z)) into n = n
  • line 3 provides a proof term for the current goal (if we wanted to be more explicit, we could have written Refl {x = n} in place of Refl).


标签: idris