Proving that Programs are Correct

The -calculus was intended as a kind of Mathematical Logic, and we shall use it as such to construct proofs about programs in our language within our language. Essentially the idea is that since the -calculus provides the definition of our language, we can require that any implementation obeys the laws of the calculus, together with additional laws which characterise the behaviour of the built-in System capabilities.

For example, suppose we want to prove that a sorting function that we have written, say merge_sort, is correct. Then since we are operating within the functional paradigm, merge_sort should be exactly equivalent to an expression of the -calculus. What does it mean to say that merge_sort is correct? There are two criteria:

This is a hard problem

Proving that programs are correct at the level of detail to which we aspire is an undecidable problem, for our approach is in effect to show that two different programs always produce the same result when given the same data, which is known to be undecidable if taken over a wide enough class of programs.

However, there is nothing in the undecidability result which says that it is impossible to prove that a particular program is correct. So, it is reasonable to attack the problem of proof with a combination of human ingenuity controlling a collection of inference rules provided as functions in the language itself.[Theoretical Foundations of Programming Languages and their Practical Realisation.

The Abstract Data-type "Theorem"

Practically, this can be realised by using an abstract data-type Theorem with the property that the only ways a language-user can get hold of a theorem are guaranteed to ensure the validity of the theorem.

A theorem has two essential components, its premises and its conclusion. Our theorems will also carry a history with them. A theorem prints as

    premises |- conclusion
For example, we might have
    Integer.? x, Integer.?y |- x+y = y+x
Which states that it doesn't matter whether you add x to y or y to x. If there are no premises, then we write simply
    |-  conclusion
For example we require:
    |-  x = x

The meaning of theorems is a bit tricky to define. Essentially, the premises are a sequence of things that look like terms of the -calculus, while the conclusion is one of these term-like things. Notionally, the premises and conclusion "evaluate" to one of the values "true" or "false", and we require of our theorems that if all the premises "evaluate" to true, so does the conclusion.

The tricky bit is that such evaluation is not constructive. This has to be so because we are interested in proving theorems about equality of functions. We'd like, for example to be able to prove that

    |-  \x. x+3 = \x. 3+x

The conclusion \x. x+3 = \x. 3+x looks like a term of the -calculus, but we can't evaluate it in the ordinary way we'd evaluate a program. Instead, we have to employ a mathematical concept of evaluation. In this particular case, the meaning of the equality can be taken to be that if each of these -abstractions is given any of a countably infinite universe of objects of values, the results are computably identical.

Theorems provid arbitration between users and implementors.

Obtaining Theorems

There are 3 ways that a user can obtain a theorem.