2

Here's a small theorem in mathematics:

Suppose u is not an element of A, and v is not an element of B, and f is an injective function from A to B. Let A' = A union {u} and B' = B union {v}, and define g: A' -> B' by g(x) = f(x) if x is in A, and g(u) = v. Then g is injective as well.

If I were writing OCaml-like code, I'd represent A and B as types, and f as an A->B function, something like

module type Q = 
  sig
   type 'a
   type 'b
   val f: 'a -> 'b
  end

and then define a functor

module Extend (M : Q) : Q = 
  struct
    type a = OrdinaryA of M.a | ExoticA
    type b = OrdinaryB of M.b | ExoticB
    let f x = match x with
        OrdinaryA t -> OrdinaryB ( M.f t)
      | Exotic A -> ExoticB
  end;;

and my theorem would be that if Q.f is injective, then so is (Extend Q).f, where I'm hoping I've gotten the syntax more or less correct.

I'd like to do the same thing in Isabelle/Isar. Normally, that'd mean writing something like

definition injective :: "('a  ⇒ 'b)  ⇒ bool"
  where "injective f  ⟷ ( ∀ P Q.  (f(P) = f(Q)) ⟷ (P = Q))" 

proposition: "injective f ⟹ injective (Q(f))"

and Q is ... something. I don't know how to make, in Isabelle a single operation analogous to the functor Q in OCaml that creates two new datatypes and a function between them. The proof of injectivity seems as if it'd be fairly straightforward --- merely a four-case split. But I'd like help defining the new function that I've called Q f, given the function f.

John
  • 509
  • 1
  • 6
  • 18

1 Answers1

1

Here's a solution. I tried to make a "definition" for the function Q, but could not do so; instead, creating a constant Q (built in strong analogy to map) let me state and prove the theorem:

theory Extensions
  imports Main
begin
text ‹We show that if we have f: 'a → 'b that's injective, and we extend 
both the domain and codomain types by a new element, and extend f in the 
obvious way, then the resulting function is still injective.›
  definition injective :: "('a  ⇒ 'b)  ⇒ bool"
    where "injective f  ⟷ ( ∀ P Q.  (f(P) = f(Q)) ⟷ (P = Q))" 

datatype 'a extension = Ordinary 'a | Exotic

fun Q ::  "('a  ⇒ 'b) ⇒ (('a extension)  ⇒ ('b extension))"  where 
   "Q f (Ordinary u) = Ordinary (f u)" |
   "Q f (Exotic) = Exotic"

lemma "⟦injective f⟧ ⟹ injective (Q f)"
  by (smt Q.elims extension.distinct(1) extension.inject injective_def)

end
John
  • 509
  • 1
  • 6
  • 18
  • I would like to make two remarks. 1: there exists a function in the standard library that identical in its behaviour to the function `injective` in your answer (see function `inj` from the theory `HOL/Fun`). 2: Usually, it is more natural to use the type constructor `set` from the theory `HOL/Set` for the statements of the theorems that are similar to the one in your question. This would allow you to state the theorem within the context of one arbitrary type τ. Of course, I am not certain what your application is. Therefore, I might be wrong. – user9716869 - supports Ukraine Mar 06 '19 at 22:20
  • I figured there was an "injective" somewhere, but it was easy to write, and it put everything in one place for this simple example. As for "set" ... it turns out to be the wrong thing to use in the larger context in which I'm working, while this "extension" thing is almost exactly right. The actual context, just FYI: constructing a projective plane from an affine plane by adding "points at infinity". – John Mar 06 '19 at 23:28