- Ever since I learned a little bit of Coq I wanted to learn to write a Coq proof of the so-called division algorithm that is actually a logical proposition:
forall n m : nat, exists q : nat, exists r : nat, n = q * m + r
- I recently accomplished that task using what I learned from Software Foundations.
- Coq being a system for developing constructive proofs, my proof is in effect a method to construct suitable values
q
andr
from valuesm
andn
. - Coq has an intriguing facility for "extracting" an algorithm in Coq's algorithm language (Gallina) to general-purpose functional programming languages including Haskell.
- Separately I have managed to write the divmod operation as a Gallina
Fixpoint
and extract that. I want to note carefully that that task is not what I'm considering here. - Adam Chlipala has written in Certified Programming with Dependent Types that "Many fans of the Curry-Howard correspondence support the idea of extracting programs from proofs. In reality, few users of Coq and related tools do any such thing."
Is it even possible to extract the algorithm implicit in my proof to Haskell? If it is possible, how would it be done?
The current copy of Software Foundations dated July 25, 2012, answers this quite concisely in the late chapter "Extraction2". The answer is that it can certainly be done, much like this:
One more trick is necessary. Instead of a
Prop
, divalg must be aType
. Otherwise it will be erased in the process of extraction.Uh oh, @Anthill is correct, I haven't answered the question because I don't know how to explain how Prof. Pierce accomplished that in his NormInType.v variant of his Norm.v and MoreStlc.v.
OK, here's the rest of my partial answer anyway.
Where "divalg" appears above, it will be necessary to provide a space-separated list of all of the propositions (which must each be redefined as a
Type
rather than aProp
) on which divalg relies. For a thorough, interesting, and working example of a proof extraction, one may consult the chapter Extraction2 mentioned above. That example extracts to OCaml, but adapting it for Haskell is simply a matter of usingExtraction Language Haskell
as above.In part, the reason that I spent some time not knowing the above answer is that I have been using the copy of Software Foundations dated October 14, 2010, that I downloaded in 2011.
Thanks to Prof. Pierce's summer 2012 video 4.1 as Dan Feltey suggested, we see that the key is that the theorem to be extracted must provide a member of
Type
rather than the usual kind of propositions, which isProp
.For the particular theorem the affected construct is the inductive Prop
ex
and its notationexists
. Similarly to what Prof. Pierce has done, we can state our own alternate definitionsex_t
andexists_t
that replace occurrences ofProp
with occurrences ofType
.Here is the usual redefinition of
ex
andexists
similarly as they are defined in Coq's standard library.Here are the alternate definitions.
Now, somewhat unfortunately, it is necessary to repeat both the statement and the proof of the theorem using these new definitions.
Back on planet Earth, here is the repeated statement of the theorem using "exists_t".
As I have omitted the proof of
divalg
, I will also omit the proof ofdivalg_t
. I will only mention that we do have the good fortune that proof tactics including "exists" and "inversion" work just the same with our new definitions "ex_t" and "exists_t".Finally, the extraction itself is accomplished easily.
The resulting Haskell file contains a number of definitions, the heart of which is the reasonably nice code, below. And I was only slightly hampered by my near-total ignorance of the Haskell programming language. Note that
Ex_t_intro
creates a result whose type isEx_t
;O
andS
are the zero and the successor function from Peano arithmetic;beq_nat
tests Peano numbers for equality;nat_rec
is a higher-order function that recurs over the function among its arguments. The definition ofnat_rec
is not shown here. At any rate it is generated by Coq according to the inductive type "nat" that was defined in Coq.Update 2013-04-24: I know a bit more Haskell now. To assist others in reading the extracted code above, I'm presenting the following hand-rewritten code that I claim is equivalent and more readable. I'm also presenting the extracted definitions Nat, O, S, and nat_rec that I did not eliminate.