HI,

On 13/12/2006, at 10:02 PM, Thorsten Altenkirch wrote:

Hi Neil,

sorry that as far as I can see nobody has yet replied to your email. I certainly have been very busy recently.

Sounds you have run a very interesting course. Can you give some more details on your symmetric definition of addition?


James and I had a short discussion on this so maybe it is also of interest to other people, although I'm perhaps preaching to the converted here.

One of the things which I wanted to show students was how you can define your own induction schema and hence refinement operators in epigram, and how doing this can really make solving problems a lot simpler. The nicest example I could come up with was proving the symmetry of addition.

Suppose n, m are Nats and you want to prove P(n, m). Well you expect to do one induction on n, and give yourself the sub-problems of proving P(0, m) and of proving P((s n), m) given P(n, m). In each of these you do an induction on m to give yourself (eventually) the tasks of proving P(0, 0); P(0, (s m)) given P(0, m); P((s n), 0) given P(n, 0); P((s n), (s m)) given P(n, m). Perhaps you might have chosen to do the induction on m first, and then the inductions on n. It really doesn't matter which order you do them in as you get the same sub-goals. But here is the neat thing which epigram lets us do: we can define and use our own induction schema to capture this pattern.

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 []
     ! plussym n m : Eq N (plus n m) (plus m n) )
------------------------------------------------------------------------ ----------------------------------

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 []
     ! addsym n m : Eq N (add n m) (add m n) )

------------------------------------------------------------------------ ----------------------------------

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 []
     ! plussym n m : Eq N (plus n m) (plus m n) )
------------------------------------------------------------------------ ----------------------------------

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 []
     ! addisplus n m : Eq N (add n m) (plus 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.


Btw, are you going to attend CATS in January?


Unfortunately not.

Cheers,
Thorsten


Best,
Neil

On 28 Nov 2006, at 23:33, neil wrote:

Hi Everyone,
More noise for this list!

I used Epigram in teaching this year, and, since summer is nearly here I thought I'd give some feedback on my experiences. All of this is very unscientific and subjective, so take with a pinch of salt.

The class was a final year BSc Hons class (Snr Hons in Scottish terms) in functional programming. Most NZ students leave at the end of 3rd year, and usually only strong students stay on for 4th year. The class also had some students who were taking taught Master's degrees. These students have a wider range of abilities. Before we started on Epigram we covered (relatively) practical Haskell programming, and some lambda calculus. Some of the students had taken a paper on computational logic, which focusses on theorem proving and logic programming, but also covers Gentzen systems.

With epigram I was aiming for  several related goals:
1) introduce the Curry-Howard/Propositions as types/proofs as programs idea, and give the flavour of programming in constructive logic 2) let students experience epigram's interactive programming environment 3) let students see dependent types doing something useful (or at least something neat)

We did various things:
a) We gave the usual logical types, and Nats, lists, equality...
b) to get a flavour of the extra power of the type system we started with lists and append in Haskell, and moved to defining lists and append in type theory. Then we moved on to defining vectors and exploring how we could use the type to express a full specification for append. c) to get a bit more of the flavour of programming constructively we proved that very Nat is either even or odd. This is similar to, and much simpler than, "either this string parses or it doesn't".

I gave the students an assignment which involved proving some `logical' stuff and defining and proving that addition is commutative.

The logic went from showing |- A & B -> B & A, up to showing that A v -A |- --A -> A, and showing --A -> A |- A v -A does not hold, and showing A v -A |- ((A -> B) -> A) -> A.

I gave them two definition for addition:
plus 0 m = m
plus n' m = (plus n m)'

and

add 0 0 = 0
add 0 n' = n'
add n' 0 = n'
add n' m' = (add n m)''

To permit the latter definition I gave them an elimination rule (and consequently a new refinement operator). Proving that add is commutative is a lot easier than proving that plus is.

The reaction of the students to epigram was, predictably, mixed. I had feared that they would complain about the UI (none were very experienced emacs users, for example) but none of them raised this as an issue. Curiously, one of them expressed a dislike for the style of incremental program development with rapid feedback! The very best students got a lot out of working with epigram. Some of the middle students found the harder assignment questions beyond them, but some of the middle students really got the idea of proofs as programs. At least one of the weaker students just didn't understand what was going on.

I intend to use epigram again next year. Two obvious things which I could improve are:
i) fewer logical examples, and more programming examples;
ii) more motivating examples of quite basic uses for dependent types;

Anyhow, I hope that this is useful to someone, and I'm happy to discuss further with anyone interested. I guess that eventually there is a paper on teaching programming in constructive type theory constructively in this somewhere.

Cheers,
Neil

School of Mathematics, Statistics and Computer Science &
Centre for Logic, Language and Computation
Victoria University
P. O. Box 600
Wellington                                         Tel +64 4 463 6732
New Zealand                          mailto:[EMAIL PROTECTED]

The information in this e-mail message is confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and destroy any copies of this e-mail.




This message has been checked for viruses but the contents of an attachment may still contain software viruses, which could damage your computer system: you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.


School of Mathematics, Statistics and Computer Science &
Centre for Logic, Language and Computation
Victoria University
P. O. Box 600
Wellington                                         Tel +64 4 463 6732
New Zealand                          mailto:[EMAIL PROTECTED]

The information in this e-mail message is confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and destroy any copies of this e-mail.


Reply via email to