From tfm%computer-lab.cambridge.ac.uk@NSFnet-Relay.AC.UK  Wed Dec  6 08:39:56 1989
Received: by iris (5.57/3.14)
        id AA06879; Wed, 6 Dec 89 08:39:56 PST
Received: from ucdavis.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
        id AA05003; Wed, 6 Dec 89 08:43:12 PST
Received: by ucdavis.ucdavis.edu (5.51/UCD1.41)
        id AA20622; Wed, 6 Dec 89 08:20:17 PST
Received: from sun.nsfnet-relay.ac.uk by vax.NSFnet-Relay.AC.UK
           via Janet with NIFTP  id aa12180; 6 Dec 89 15:29 GMT
Received: from steve.cl.cam.ac.uk by scaup.Cl.Cam.AC.UK id aa14745;
          6 Dec 89 15:32 GMT
Date: Wed, 6 Dec 89 15:27:49 GMT
From: Tom Melham <tfm%computer-lab.cambridge.ac.uk@NSFnet-Relay.AC.UK>
To: info-hol%clover.ucdavis.edu@NSFnet-Relay.AC.UK
Subject: an inconsistent axiom for lists.
Message-Id:  <8912061532.aa14745@scaup.Cl.Cam.AC.UK>

A Little HOL Puzzle
-------------------

Here's a little proof which had me puzzled for a while, and which
might be of some minor interest to readers of info-hol.

Lars Rossen (Technical University of Denmark) recently did an interesting
formalization of Mary Sheeran's RUBY language in the HOL system (old HOL,
not HOL88).  One component of this formalization was an axiomatization of
"l-lists", a type of lisp-like lists, whose elements could be of mixed
types. E.g. the list:

   [1;T;2]

would be a legally-typed value of type l-list.  This kind of non-homogenous
list is, of course, not allowed in the type (*)list.

Now, Lars formalized l-lists by introducing two constants:

   LNIL:llist   and    LCONS:*->llist->llist

where llist is an undefined type constant standing for the set of all non-
homogenous lists. He then postulated an axiom to characterize the type llist,
in the form of the primitive recursion theorem:

   !x:**. !f:**->*->llist->**. ?!fn:llist->**.
      (fn LNIL) = x /\
      (!h t. fn(LCONS h t) = f (fn t) h t

This whole scheme is completely analogous to the approach to the built-in type
(*)list---except that llist is a type constant, and the functions LNIL & LCONS
have types that reflect this difference.  (In particular, LCONS has
type *->llist->llist, so that it can be applied to a value of any type *,
and you always get a list).

The problem with this scheme, as Lars clearly recognized and discussed in his
technical report on the work (ID-TR 1989-61 from the Technical University of
Denmark), is that it introduces the possibility of inconsistency.

The puzzle I set myself, was to prove that this axiomatization of lists in
fact does introduce inconsistency...by deriving |- F from it.  I worked for a
while on the problem, and finally came up with the following proof, which
readers may find interesting.  The proof, however, seems to be far too
complicated.  Can anyone see an easier proof of |- F from the llist axiom
given above?

The idea of the proof
---------------------

Start with the list axiom postulated by Lars:

    new_type 0 `llist`;;

    new_constant (`LNIL`, ":llist");;

    new_constant (`LCONS`, ":* -> llist -> llist");;

    let ax = new_axiom
             (`ax`, "!x:**. !f:** -> * -> llist -> **.
                     ?!fn:llist -> **.
                     (fn LNIL = x) /\
                     (!h:*. !t. fn(LCONS h t) = f (fn t) h t)");;

Then derive falsity from this axiomatization as follows. First prove that
list axiom ax (above) implies that the types

        (*)list and (**)list

have the same number of elements, where * and ** are type variables, and
"list" is the usual list type-operator.  We have now finished using ax.
Then take:

        * = one   and   ** = num->bool

and (via Cantor's diagonal argument) you're done!  All you have to do is
show that (one)list and (num->bool)list in fact cannot have the same number
of values.  This is done by showing that:

      (1) (one)list has the same number of values as num

      (2) so (from ax) is follows that (num->bool)list has the
          same number of elements as num.

      (3) hence, num has the same number of elements as num->bool.

      (4) but by Cantor's proof, num has strictly fewer elements than
          num->bool, so there's a contradiction.

The HOL code for the proof is appended to this message.  Note, in
passing, that this proof demonstrates a good use for the built-in
function: prove_rec_fn_exists. (This runs only in HOL88).

My question to info-hol readers is: does it have to be this complicated?

Tom

PS: I should add, Lars' work on formalizing RUBY in HOL does not
seem to depend in any fundamental way on this inconsistent list
axiomatization, and indeed, he is careful to avoid the inconsistency.
Furthermore, the other parts of Lars' formalization are quite sound.

---------------------------------------------------------------------

% --------------------------------------------------------------------- %
% DESCRIPTION: Proof of |- F from Lars Rossen's list axiom.             %
% AUTHOR:      Tom Melham                                               %
% DATE:        6 December 1989.                                         %
% --------------------------------------------------------------------- %

% --------------------------------------------------------------------- %
% First, introduce the new type llist, the constants LNIL and LCONS,    %
% and postulate the axiom for lists.                                    %
% --------------------------------------------------------------------- %

new_theory `temp`;;

new_type 0 `llist`;;

new_constant (`LNIL`, ":llist");;

new_constant (`LCONS`, ":* -> llist -> llist");;

let ax = new_axiom
          (`ax`, "!x:**. !f:** -> * -> llist -> **.
                  ?!fn:llist -> **.
                  (fn LNIL = x) /\
                  (!h:*. !t. fn(LCONS h t) = f (fn t) h t)");;

close_theory `ax`;;

let llist_INDUCT = prove_induction_thm ax;;

% --------------------------------------------------------------------- %
% Now, prove that llist has the same number of elements as (*)list      %
% --------------------------------------------------------------------- %

let f_exists = prove_rec_fn_exists ax
               "(f LNIL = NIL) /\ (!h t. f(LCONS (h:*) t) = CONS h (f t))";;

let g_exists = prove_rec_fn_exists list_Axiom
               "(g NIL = LNIL) /\ (!h t. g(CONS (h:*) t) = LCONS h (g t))";;

let llist_Iso_list =
    TAC_PROOF(([], "?f:llist->(*)list. ?g:(*)list->llist.
                    (f o g = I) /\ (g o f = I)"),
             MAP_EVERY STRIP_ASSUME_TAC [f_exists; g_exists] THEN
             MAP_EVERY EXISTS_TAC ["f:llist->(*)list";"g:(*)list->llist"] THEN
             CONJ_TAC THEN CONV_TAC FUN_EQ_CONV THEN
             PURE_REWRITE_TAC [o_THM;I_THM] THENL
             [INDUCT_THEN list_INDUCT ASSUME_TAC;
              INDUCT_THEN llist_INDUCT ASSUME_TAC] THEN
             ASM_REWRITE_TAC []);;

% --------------------------------------------------------------------- %
% Now, use llist_Iso_list to infer that (one)list has the same number of%
% elements as (num->bool)list.  Note that this is just false, since the %
% type (one)list has a countable number of values and (num->bool)list   %
% does not.  This will be the basis of the inconsistency proof.         %
% --------------------------------------------------------------------- %

% First, a conversion that skips past /\, = and the first "o"           %
let CONV conv =
    let cnv = (RATOR_CONV(RAND_CONV(RATOR_CONV(RAND_CONV conv)))) in
    RAND_CONV cnv THENC (RATOR_CONV(RAND_CONV cnv));;

% Now, prove that (one)list == (num->bool)list                          %
let one_iso_num_to_bool =
    TAC_PROOF(([], "?f:(one)list->(num->bool)list. ?g.
                    (f o g = I) /\ (g o f = I)"),
      STRIP_ASSUME_TAC (INST_TYPE [":one",":*"] llist_Iso_list) THEN
      STRIP_ASSUME_TAC (INST_TYPE [":num->bool",":*"] llist_Iso_list) THEN
      EXISTS_TAC "(f':llist->(num->bool)list) o (g:(one)list->llist)" THEN
      EXISTS_TAC "(f:llist->(one)list) o (g':(num->bool)list->llist)" THEN
      PURE_ONCE_REWRITE_TAC [o_ASSOC] THEN
      CONV_TAC (CONV (REWRITE_CONV (SYM(SPEC_ALL o_ASSOC)))) THEN
      ASM_REWRITE_TAC [I_o_ID]);;

% --------------------------------------------------------------------- %
% Now we prove that (one)list has the same number of elements as num,   %
% and hence that num has the same number of elements as (num->bool)list %
% --------------------------------------------------------------------- %

let f_exists = prove_rec_fn_exists list_Axiom
               "(f NIL = 0) /\
                (!h:one. !t. f(CONS h t) = SUC(f t))";;

let g_exists = prove_rec_fn_exists num_Axiom
               "(g 0 = NIL) /\
                (g (SUC n) = CONS one (g n))";;

let one_Induct = prove_induction_thm one_Axiom;;

let one_iso_num =
    TAC_PROOF(([], "?f:(one)list->num. ?g. (f o g = I) /\ (g o f = I)"),
              MAP_EVERY STRIP_ASSUME_TAC [f_exists; g_exists] THEN
              MAP_EVERY EXISTS_TAC ["f:one list->num";"g:num->(one)list"] THEN
              CONJ_TAC THEN CONV_TAC FUN_EQ_CONV THEN
              PURE_REWRITE_TAC [o_THM;I_THM] THENL
              [INDUCT_THEN INDUCTION ASSUME_TAC;
               INDUCT_THEN list_INDUCT ASSUME_TAC THENL
               [ALL_TAC;INDUCT_THEN one_Induct (K ALL_TAC)]] THEN
              ASM_REWRITE_TAC []);;

let num_iso_num_to_bool =
    TAC_PROOF(([], "?f:num->(num->bool)list. ?g.(f o g = I) /\ (g o f = I)"),
      MAP_EVERY STRIP_ASSUME_TAC [one_iso_num_to_bool;one_iso_num] THEN
      EXISTS_TAC "(f:(one)list->(num->bool)list) o (g':num->(one)list)" THEN
      EXISTS_TAC "(f':(one)list->num) o (g:(num->bool)list->(one)list)" THEN
      PURE_ONCE_REWRITE_TAC [o_ASSOC] THEN
      CONV_TAC (CONV (REWRITE_CONV (SYM(SPEC_ALL o_ASSOC)))) THEN
      ASM_REWRITE_TAC [I_o_ID]);;

% --------------------------------------------------------------------- %
% Now, from num_iso_num_to_bool, it follows that we can enumerate all   %
% the functions of type num->bool.  We first show that we can enumerate %
% all num->bool lists of length one.                                    %
% --------------------------------------------------------------------- %

% element-wise version of the theorem in question                       %
let lemma = REWRITE_RULE [o_THM;I_THM]
            (CONV_RULE (DEPTH_CONV FUN_EQ_CONV) num_iso_num_to_bool);;

let enum_len_one =
    TAC_PROOF(([], "?fn. !f:num->bool. ?n:num. fn n = [f]"),
              STRIP_ASSUME_TAC lemma THEN
              EXISTS_TAC "f:num->(num->bool)list" THEN
              X_GEN_TAC "fun:num->bool" THEN
              EXISTS_TAC "g[fun:num->bool]:num" THEN
              ASM_REWRITE_TAC []);;

let hd_exists = prove_rec_fn_exists list_Axiom
                "hd (CONS (h:num->bool) t) = h";;

let enum =
    TAC_PROOF(([], "?fn:num->(num->bool). !f. ?n. f = fn n"),
      STRIP_ASSUME_TAC enum_len_one THEN
      STRIP_ASSUME_TAC hd_exists THEN
      EXISTS_TAC "\n:num. hd((fn:num->(num->bool)list) n):num->bool" THEN
      CONV_TAC (DEPTH_CONV BETA_CONV) THEN
      X_GEN_TAC "fun:num->bool" THEN
      FIRST_ASSUM
         (\th. STRIP_THM_THEN MP_TAC(SPEC "fun:num->bool" th) ? NO_TAC) THEN
      DISCH_THEN (\th. EXISTS_TAC "n:num" THEN SUBST1_TAC th) THEN
      ASM_REWRITE_TAC []);;

% --------------------------------------------------------------------- %
% We now prove |- F via cantor's proof from enum.                       %
% --------------------------------------------------------------------- %

let FALSITY =
    TAC_PROOF(([], "F"),
        X_CHOOSE_THEN "fun:num->(num->bool)" MP_TAC enum THEN
        DISCH_THEN (MP_TAC o SPEC "\n:num. ~(fun n n)") THEN
        CONV_TAC (DEPTH_CONV FUN_EQ_CONV) THEN
        CONV_TAC (DEPTH_CONV BETA_CONV) THEN
        DISCH_THEN (X_CHOOSE_THEN "N:num" (MP_TAC o SPEC "N:num")) THEN
        BOOL_CASES_TAC "fun (N:num) (N:num):bool" THEN
        REWRITE_TAC[]);;

% --------------------------------------------------------------------- %
% It follows that ax cannot consistently be added to the logic.         %
% --------------------------------------------------------------------- %

