## Inverse typechecker and theorem proving in intuitionistic and classical logics

Another cool demonstration from Oleg:

I'd like to point out a different take on Djinn:

http://cvs.sourceforge.net/viewcvs.py/kanren/kanren/mini/logic.scm

The first defines the Hindley-Milner typechecking relation for a
language with polymorphic let, sums and products. We use the Scheme
notation for the source language (as explained at the beginning of the
first file); ML or Haskell-like notations are straightforward. The
notation for type terms is infix, with the right-associative arrow.

The typechecking relation relates a term and its type: given a term we
obtain its type. The relation is pure and so it can work in reverse: given a type, we can obtain terms that have this type. Or, we can give a term with blanks and a type with blanks, and ask the relation to fill in the blanks.

As an example, the end of the file type-inference.scm shows the derivation for the terms call/cc, shift and reset from their types in the continuation monad. Given the type

(((a -> . ,(cont 'b 'r)) -> . ,(cont 'b 'b)) -> . ,(cont 'a 'b))

we get the expression for shift:

   (lambda (_.0) (lambda (_.1)
((_.0 (lambda (_.2) (lambda (_.3) (_.3 (_.1 _.2)))))
(lambda (_.4) _.4))))


It took only 2 milli-seconds.

More interesting is using the typechecker for proving theorems in
intuitionistic logic: see logic.scm. We formulate the proposition in types, for example:

  (,(neg '(a * b)) -> . ,(neg (neg (,(neg 'a) + ,(neg 'b)))))

This is one direction of the deMorgan law. In intuitionistic logic,
deMorgan law is more involved:

	NOT (A & B) == NOTNOT (NOT A | NOT B)

The system gives us the corresponding term, the proof:

(lambda (_.0)
(lambda (_.1)
(_.1 (inl (lambda (_.2)
(_.1 (inr (lambda (_.3) (_.0 (cons _.2 _.3))))))))))


The de-typechecker can also prove theorems in classical logic,
via double-negation (aka CPS) translation. The second part of
logic.scm demonstrates that. We can formulate a proposition:

(neg (neg (,(neg 'a) + ,(neg (neg 'a)))))

and get a (non-trivial) term

	(lambda (_.0) (_.0 (inr (lambda (_.1) (_.0 (inl _.1))))))

It took only 403 ms. The proposition is the statement of the Law of
Excluded Middle, in the double-negative translation.

So, programming languages can help in the study of logic.

## Comment viewing options

### Oleg here uses Mini-Kanren,

Oleg here uses Mini-Kanren, the LP system for Scheme that accompanies The Reasoned Schemer. This book and system are worth checking out; besides being extremely educational, I'm finding the system easy and useful. Plus, since it's so simple and small (+/- 100 lines!), it's a snap to tinker with the interior.

I built a type inference example similar to the one Oleg presents up there (but not as good) in half a day, as a proof of concept.

Plus, one final thing: Scheme is the ideal language to do type inference, because there are none of those stupid types to get in the way.

### Right

I should have mentioned that this is based on Kanren. TRS was discussed here at length.

### Actually...

Actually, I just wanted to get in on the Reasoned Schemer love-fest, since I missed it the first time 'round.

### Or, just use Coq

This:
 Definition cont (a r : Set) := (a->r)->r.

 Lemma shift : forall (a b r : Set), ((a -> (cont b r))->(cont b b)) -> (cont a b). firstorder. Qed. 

Extraction shift. 
yields
 let shift h h0 = h (fun h1 h2 -> h2 (h0 h1)) (fun h1 -> h1)