Proofs are not programs

The Curry-Howard correspondence can be pithily described as saying “proofs = programs”. The statement is short, alliterative, and rather beautiful. As a professional mathematician I know exactly what a proof is; as an amateur programmer I have a pretty clear idea about what a program is, and the concept that they might be in some sense the same thing is both enigmatic and appealing. A proof is a logical sequence of statements deducing a theorem from the the rules of maths; a program is a logical sequence of commands producing valid code from the rules of the programming language being used. When learning Lean I saw the correspondence in action many times, and so it actually took quite some time for the penny to drop: the Curry-Howard correspondence is not actually true.

Of course something is true, but what is not true is any statement of this form where “proof” is interpreted as “what the pure mathematicians in my department do”. What is true is that if you stick to constructive maths or intuitionistic logic or one of the flavours of maths where you’re not allowed to use the axiom of choice or the law of the excluded middle — in other words a version of maths which is unrecognisable to over 95% of pure mathematicians working in mathematics departments — then you might be in good shape. But that is not what I see happening in my mathematics department or the other mathematics departments which I’ve had experience of. Some proofs are not programs.

Here’s an example of a proof which is not a program. The original proof that the class numbers of imaginary quadratic fields tended to infinity was the following rather extraordinary argument. First Landau showed that the theorem was true assuming that a certain generalisation of the Riemann Hypothesis was true, and then Heilbronn managed to show that the theorem was true assuming that this generalisation was false! See for example Keith Conrad’s comment on this mathoverflow question, and for more details see p359 of the book “A Classical Introduction to Modern Number Theory” by Ireland and Rosen (I have a copy of this book in my office if any Imperial students are interested in seeing more details).

The analogous situation for programs would be something like the following. Your boss asks you to write some computer code to do a certain task so your company can release their new product. A week later you enter their office with two USB sticks, explaining that one of them does the task if the Riemann hypothesis is true, and the other one does the task if the Riemann hypothesis is false. What you seem to have done, on the face of it, is proved that the code your boss wanted exists. You might also have lost your programming job 😉 In fact it’s not even 100% clear that you have proved that the code exists — what if we replace the Riemann Hypothesis in this story by one of these weird unprovable logic statements like the continuum hypothesis, which is true in some models of maths and false in others? Then where’s the program?

But actually it’s even worse than that. In my last blog post, I gave an example of a computable bijective function which did not have a computable inverse. A similar sort of argument shows that the following proof:

Theorem. If f: X \to Y is a surjective function, then there exists a map g: Y \to X such that f\circ g: Y \to Y is the identity function.

Proof. Define g thus: if y\in Y then choose x\in X with f(x)=y (possible by surjectivity of f) and define g(y) to be this x. The fact that f(g(y))=y is true by definition. QED.

does not correspond to a program. The theorem is just the axiom of choice in disguise, and the axiom of choice is about as non-constructive as you can get. Programs are algorithms. The axiom of choice says that we can do something when there is no algorithm.

What is a Lean file then?

So this a bit confusing, because I can prove that theorem above in Lean:

noncomputable def g {X Y : Type} {f : X → Y} (hf : function.surjective f)
  (y : Y) : X := classical.some (hf y)

lemma g_prop {X Y : Type} {f : X → Y} (hf : function.surjective f) 
  (y : Y) : f (g hf y) = y := classical.some_spec (hf y)

theorem has_right_inverse_of_surjective (X Y : Type) (f : X → Y)
  (hf : function.surjective f) :
  ∃ g : Y → X, ∀ y : Y, f (g y) = y := ⟨g hf, g_prop hf⟩

and that looks like code to me. But not all computer files are computer programs. As an example, consider a LaTeX file. The LaTeX program is the program, the LaTeX file is just the input to the program, and the output is typically a pdf file.

Lean itself is a program, but the Lean files which people make are not all programs. Some of them are though! Some Lean files (which use constructive logic and only computable functions) are turned into bytecode when run through Lean, and bytecode is a program. But no bytecode is generated for the definition of the function g above because it is noncomputable, and that stops the proof has_right_inverse_of_surjective from ever being a program. Lean itself can verify that the proof is correct, but the proof itself is not a program.

I am still getting to grips with all this computer science malarkey. I asked a bunch of questions about this stuff when writing this blog post, on this thread in the Lean chat (login required), and thanks as ever to Mario Carneiro for answering most of them.

About xenaproject

The Xena Project aims to get mathematics undergraduates (at Imperial College and beyond) trained in the art of formalising mathematics on a computer. Why? Because I have this feeling that digitising mathematics will be really important one day.
This entry was posted in computability and tagged , , , . Bookmark the permalink.

5 Responses to Proofs are not programs

  1. aaron.stump says:

    Distressingly, as you may know, quite a subliterature has developed extending the Curry-Howard correspondence to classical logic. The seminal paper is by Timothy Griffin, “A formulae-as-type notion of control” (https://dl.acm.org/citation.cfm?id=96714). I have a blog post explaining why I think this is not a good idea for dependently typed programming (https://queuea9.wordpress.com/2018/10/17/why-i-no-longer-believe-in-computational-classical-type-theory/).

    Like

  2. ice1000 says:

    Why not parameterize all LEM (or AC) based theorems with a proof of LEM (or AC)? The postulated LEM (like a “P ∨ ¬ P”) allows you to constructively work with LEM-based theorems, and they are still programs.

    Like

    • xenaproject says:

      So for P’s for which P or not P is not provable classically, your parameter will essentially be an axiom, which from a computer science point of view is a function for which the code is not available. So you’ll get a program but it will depend on “undefined constants” which aren’t present in the statement of the theorem but which are present in the proof. In particular you won’t be able to run the program to construct an explicit term of the type corresponding to your theorem, you’ll just an abstract existence proof that assuming LEM or whatever there is a term of this type. This is consistent with what mathematics looks like to me. Every sufficiently large natural is the sum of 7 natural cubes, infinitely many are not the sum of 3 natural cubes, so we have an as yet uncomputed value g(3), a proof that it exists, but no program to run which will compute it.

      Liked by 1 person

  3. aaron.stump says:

    What one gets with computational classical type theory is more subtle: when you ask if P or not P holds, you are told it is not P (always). How can you make use of negative information? Ultimately by contradicting it with a proof of P, at which point the computation backtracks (with what is called a “control operator” in CS) and presents you with that proof of P back at the original point when you were first given a proof of not P.

    This is a confusing basis for programming with properties, as I argue in my blog post. But it is computational, and not the same as getting stuck on an axiom.

    Like

  4. Davide Barbarossa says:

    Just two clarifications which I hope could be interesting:
    – As already pointed out in previous comments, it is indeed possible to lift the Curry-Howard correspondence to classical logic proofs; there are actually many ways of doing so, all based on the idea that “reasoning by contradiction = backtracking via control operators”. A notable one is lambda-mu-calculus: https://link.springer.com/chapter/10.1007%2FBFb0013061.
    – A different point emerges when considering “extra-logical” axioms, particularly the “non-constructive” ones, such as the axiom of choice you mention. An idea could be to associate new “programming instructions” with such axioms, as in classical logic for which Griffin’s intuition was to use control operators. But for “extra-logical” axioms it seems difficult to have similar intuitions. However, some years ago J.-L. Krivine introduced a (beautiful!) framework in which this kind of constructions can be carried out: it is Krivine’s classical realizability (https://www.irif.fr/~krivine//articles/Luminy04.pdf). For instance, the weaker forms of the axiom of choice are easily treated via “clock like” instructions. The full axiom of choice was an open question but recently it seems that he has been able to include it: https://arxiv.org/abs/2006.05433.
    We can now understand the Curry-Howard correspondence also in the sense that we can extract, from “every” mathematical proof (here “every” means the ones formalizable inside ZF+AC), a program which “justifies” (in Krivine’s sense) the theorem proved.

    Like

Leave a comment