A research blog about programming languages, formal logics, software development and their interactions, by Matthias Puech.

Typeful disjunctive normal form

by Matthias Puech

This is the answer to last post’s puzzle. I gave an algorithm to put a formula in disjunctive normal form, and suggested to prove it correct in OCaml, thanks to GADTs. My solution happens to include a wealth of little exercises that could be reused I think, so here it is.

I put the code snippets in the order that I think is more pedagogical, and leave to the reader to reorganize them in the right one.

First, as I hinted previously, we are annotating formulas, conjunctions and disjunctions with their corresponding OCaml type, in order to reason on these types:

What we are eventually looking for is a function dnf mapping an 'a form to a 'b disj, but now these two must be related: they must represent two equivalent formulae. So, correcting what I just said: dnf must return the pair of a 'b disj and a proof that 'a and 'b are equivalent. This pair is an existential type, which is easily coded with a GADT (we do similarly for conjunctions):

It seems more verbose, but since the functions now return existentials, we need to deconstruct them and pass them around. I abstracted over the combinators that compose the proofs of equivalence lemma1…lemma5, we’ll deal with them in a moment. For now, you can replace them by Obj.magic and read off their types with C-c C-t to see if they make sense logically. Look at the last function’s type. It states, as expected: for any formula , there exists a disjuctive normal form such that .

Now on this subject, what is it for two types to be equivalent? Well, that’s the “trick”: let’s just use our dear old Curry-Howard correspondence! 'a and 'b are equivalent if there are two functions 'a -> 'b and 'b -> 'a (provided of course that we swear to use only the purely functional core of OCaml when giving them):

type ('a, 'b) equiv = ('a -> 'b) * ('b -> 'a)

Now we can state and prove a number of small results on equivalence with respect to the type constructors we’re using (pairs and unions). Just help yourself into these if you’re preparing an exercise sheet on Curry-Howard :)

Note that I only needed the previous primitives to prove these lemmas (and as such to define my functions), so we can even make the type equiv abstract, provided that we are giving a complete set of primitives (which is not the case here). Although I’m not sure what it would buy us…

5 Comments to “Typeful disjunctive normal form”

I spent bunch of time last week trying to write a solution using your initial definition of equiv type. I just got bunch of crazy type errors and I gave up.

So instead of my solution, here is your solution again but with a small tweak.

I used definition of equivalence from your last post (adding necessary variants). This gives you a proof tree instead of a conversion function as a proof.

I’m including just the parts different than your code. (I defined or_ and and_ types, I thought it might be easier to read). This works with ‘a atom=int or ‘a atom = ‘a or being abstract type but only in 4.01. In 4.00.1 it doesn’t compile.

As for the question of whether you want to make equiv abstract, that could buy you some efficiency in runtime. You could just define primitives in the mli and just have implementation of all primitives be essentially no-op, returning (None : Obj.magic) or something similar.

When you just have type equivalence (in OCaml sense) you can even avoid Obj.magic and still pay almost no runtime cost (I don’t think that would work here because we have boolean algebra equivalence which compiler can’t deduce on it’s own, but I don’t really understand the whole thing).