3

I found out that plus function for Nats is implemented in this way

total plus : (n, m : Nat) -> Nat
plus Z right        = right
plus (S left) right = S (plus left right)

I wonder if there is particular reason not to pattern match on the second argument as well like here:

total plus : (n, m : Nat) -> Nat
plus Z right        = right
plus left Z         = left
plus (S left) right = S (plus left right)

As I see for the moment this implementation would make life simpler in many proofs and code. For example

total plusZeroRightNeutral : (left : Nat) -> left + 0 = left
plusZeroRightNeutral Z     = Refl
plusZeroRightNeutral (S n) =
  let inductiveHypothesis = plusZeroRightNeutral n in
    rewrite inductiveHypothesis in Refl

would look like plusZeroLeftNeutral :

total plusZeroRightNeutral : (left : Nat) -> left + 0 = left
plusZeroRightNeutral left = Refl

In real life we don't even need to use plusZeroLeftNeutral theorem because Idris can do pattern matching automatically (as it already mentioned in the answer to this question: Concatenation of two vectors - why are lengths not treated as commutative? ).

So why not add extra cases to make life easier?

vrom911
  • 694
  • 1
  • 5
  • 16
  • Have you tried proving the new `plusZeroLeftNeutral` lemma as you suggest? – Anton Trunov Mar 19 '18 at 08:42
  • @AntonTrunov Hmm, it doesn't work, but it doesn't make any sense to me. I would love to see explanation even if that is completely incorrect. – vrom911 Mar 19 '18 at 11:31

1 Answers1

4

Actually, plusZeroLeftNeutral cannot be proved with just Refl.

When you use Refl you are saying: "this holds by computation" (another name for this is definitional equality, or judgemental equality).

But how do we compute left + 0 (i.e. plus left Z for the Nat type)? Essentially, Idris processes function definitions clause by clause from top to bottom, and in our case it first looks at plus Z right clause. At this point Idris needs to decide if left is Z, but it cannot, because we have not destructed left. Idris cannot skip the first clause and go to plus left Z clause.

Now, with this alternative definition for plus one does not need induction for the proof of right neutrality of addition:

total plusZeroRightNeutral : (left : Nat) -> plus left 0 = left
plusZeroRightNeutral Z = Refl
plusZeroRightNeutral (S _) = Refl

But on the other hand, many proofs become long-winded because they now need more pattern-matching. Let's take the associativity of addition. Here is a possible proof for this fact for the original definition of plus:

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

And here as the corresponding proof for the modified plus:

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

Here you are forced to destruct the second arguments of the occurrences of plus function simply because those block evaluation, but you need to move S constructors out of the way to be able to utilize your induction hypothesis.

Anton Trunov
  • 15,074
  • 2
  • 23
  • 43
  • 1
    Conor McBride explains this thing in his CS410 (2017) course, see [Lecture 3 (Proof by Induction), around 21:33](https://youtu.be/8xFT9FPlm18?t=1293). – Anton Trunov Mar 29 '18 at 12:10