Hello Neil,
I had liked your logic examples concerning decidability of propositions, stability and the Peirce law as a nice addendum to the logic section of Conor's and Peter Hancock's lecture notes, which are really worth a read as they take the epigram systems Mise en Scène approach to program development further than ever. But concerning your definition of addition... * Am 14.12.06 schrieb neil: ------------------------------------------------------------------------------ [If we have:] ------------------------------------------------------------------------------ ( n : N ! data (-------! where (----------! ; !------------! ! N : * ) ! zero : N ) ! succ n : N ) ------------------------------------------------------------------------------ [we can happily define:] ------------------------------------------------------------------------------ ( p, q : N ! ! ! ! ( x, y : N ! ! ! !-----------! ! ! ! C x y : * ) ! ! ! ! d : C zero zero ! ! ! ! ( n : N ; u : C zero n ! ! ! !-------------------------! ! ! ! e n u : C zero (succ n) ) ! ! ! ! ( m : N ; v : C m zero ! ( r, s : N ; w : C r s ! ! ! !-------------------------! ; !-------------------------------! ! ! ! f m v : C (succ m) zero ) ! g r s w : C (succ r) (succ s) ) ! let !------------------------------------------------------------------! ! dblnatrec p q C d e f g : C p q ) dblnatrec p q C d e f g <= rec p { dblnatrec p q C d e f g <= case p { dblnatrec zero q C d e f g <= rec q { dblnatrec zero q C d e f g <= case q { dblnatrec zero zero C d e f g => d dblnatrec zero (succ q) C d e f g => e q (dblnatrec zero q C d e f g) } } dblnatrec (succ p) q C d e f g <= rec q { dblnatrec (succ p) q C d e f g <= case q { dblnatrec (succ p) zero C d e f g => f p (dblnatrec p zero C d e f g) dblnatrec (succ p) (succ q) C d e f g => g p q (dblnatrec p q C d e f g) } } } } ------------------------------------------------------------------------------ [We can now define addition using dblnatrec to do the refinement for us:] ------------------------------------------------------------------------------ ( a, b : N ! let !-------------! ! add a b : N ) add a b <= dblnatrec a b { add zero zero => zero add zero (succ n) => succ n add (succ m) zero => succ m add (succ r) (succ s) => succ (succ (add r s)) } ------------------------------------------------------------------------------ [Not the first definition of addition you thought of, and there is ! !certainly some redundancy in there but... ! ! ! !So, let's do some exercises. Fire up epigram, load the definitions so! !far and define: ] ------------------------------------------------------------------------------ ( A : * ; a, b : A ! data !-------------------! where (---------------! ! Eq A a b : * ) ! eq : Eq A a a ) ------------------------------------------------------------------------------ [and this handy lemma:] ------------------------------------------------------------------------------ ( p : Eq N n m ! let !-----------------------------------! ! eqsucc p : Eq N (succ n) (succ m) ) eqsucc p <= case p { eqsucc eq => eq } ------------------------------------------------------------------------------ [and the definition of addition that you probably did first think of:] ------------------------------------------------------------------------------ ( n, m : N ! let !--------------! ! plus n m : N ) plus n m <= rec n { plus n m <= case n { plus zero m => m plus (succ n) m => succ (plus n m) } } ------------------------------------------------------------------------------ [Now, try to elaborate:] ------------------------------------------------------------------------------ ( n, m : N ! let !------------------------------------------! ! plussym n m : Eq N (plus n m) (plus m n) ) plussym n m [] ------------------------------------------------------------------------------ [using rec and case on n and m to refine the problem.! ! ! !Now see what happens when you elaborate: ] ------------------------------------------------------------------------------ ( n, m : N ! let !---------------------------------------! ! addsym n m : Eq N (add n m) (add m n) ) addsym n m [] ------------------------------------------------------------------------------ [using dblnatrec n m to refine the problem. ! ! ! !OK, so that was a bit of a cheat, since we did not solve the same! !problem. ! ! ! !Now elaborate: ] ------------------------------------------------------------------------------ [ ( n, m : N !! !let !------------------------------------------!! ! ! plussym n m : Eq N (plus n m) (plus m n) )! ! ! ! plussym n m [] ] ------------------------------------------------------------------------------ [using dblnatrec n m to refine the problem. You get exactly the same! !sub-problems as when refining using rec and case, but you get them ! !more easily. ! ! ! !You can also elaborate: ] ------------------------------------------------------------------------------ ( n, m : N ! let !-------------------------------------------! ! addisplus n m : Eq N (add n m) (plus n m) ) addisplus n m [] ------------------------------------------------------------------------------ [(Proving the transitivity of equality helps here, of course.) ! ! ! !There is lots more fun to be had here, and is clearly a lot more to! !explore on how to use epigram to define induction schemas to make ! !programming easier. This is one of the features of epigram which I ! !think is really attractive. ] ------------------------------------------------------------------------------ ... I'd like to note that you've lost definitional left-absorption this way: ------------------------------------------------------------------------------ inspect (lam n : N => add zero n) => (lam n => add zero n) : all n : N => N ------------------------------------------------------------------------------ inspect (lam n : N => plus zero n) => (lam n => n) : all n : N => N ------------------------------------------------------------------------------ Moreover, you can define addition which easily commutes directly via case analysis without giving up left-absorption. ------------------------------------------------------------------------------ ( a, b : N ! let !-------------! ! add a b : N ) add a b <= rec a { add a b <= case a { add zero b => b add (succ a) b <= case b { add (succ a) zero => succ a add (succ a) (succ b) => succ (succ (add a b)) } } } ------------------------------------------------------------------------------ inspect (lam n : N => add zero n) => (lam n => n) : all n : N => N ------------------------------------------------------------------------------ ( a, b : N ! let !--------------------------------! ! addsym a b : add a b = add b a ) addsym a b <= rec a { addsym a b <= case a { addsym zero b <= case b { addsym zero zero => refl addsym zero (succ b) => refl } addsym (succ a) b <= case b { addsym (succ a) zero => refl addsym (succ a) (succ b) => eqsucc (eqsucc (addsym a b)) } } } ------------------------------------------------------------------------------ This only reassures me why I prefer case analysis over giving a matrix of constructors in one go. But it could be worse. With your definition the behaviour is at least directly readable from the program, which it would not if it had been mine compiled away from a definition given by pattern matching (with a take-the-first-match semantics). Cheers, Sebastian