CentraleSupélecDépartement informatique
Plateau de Moulon
3 rue Joliot-Curie
F-91192 Gif-sur-Yvette cedex
Exemple de théories Isabelle/HOL

Curryfication

Curryfication.thy

theory Curryfication

imports Main

begin

section ‹Curryfication›

text ‹
  Curryfication, named after Haskell Curry, is a way to represent fonctions
  of several arguments with only functions of one argument. 
  In Isabelle, functions are in curryfied form:
     f: A × B → C
        (x, y) ↦ z
   is written as:
     f: A → (B → C)
        x ↦ (λy. z)
   so "f x" is a function which takes the second argument of f to provide the result,
   and "f x y" is read as "(f x) y"
›

term "(+)" ― ‹the "+" function›
value "(+) (2::int) 3"

text ‹Define sum as the function which returns the sum of two integers›
definition sum:: "int ⇒ int ⇒ int"
where "sum m n = m + n"

text ‹Check that it works as expected›
value "sum 2 3"

text ‹We can partially apply sum to one argument to define the increment function›
abbreviation "inc ≡ sum 1"

value "inc 41"

end

Termes, types, définition d'un type inductif

Exemple.thy

theory Exemple

imports Main

begin
text ‹Examples of terms›
term "a+b"
term "(a::nat)+b"

text ‹Examples of types›
typ "nat"
typ "nat ⇒ nat"
typ "nat ⇒ nat ⇒ nat"

text ‹Check the default associativity›
typ "nat ⇒ (nat ⇒ nat)"
typ "(nat ⇒ nat) ⇒ nat"

text ‹Pairs and tuples›
typ "nat × nat"

term "(0::nat, 0::nat)"
term "(0::nat, 0::nat, 0::nat)"
term "(0::nat, (0::nat, 0::nat))"
term "((0::nat, 0::nat), 0::nat)"

text ‹A simple inductive type for sequences›
datatype 'a seq =
  Empty ("∅")
| Append "'a seq" "'a" (infixl "." 60)

term "∅ . 0"
term "Append Empty 0"
term "∅ . (0::nat)"
term "∅ . (0::nat) . 1"
term "∅ . 0 . (1::nat)"

text ‹An inductive function defined on an inductive type›
fun len :: "'a seq ⇒ nat"
where
  "len ∅ = 0"
| "len (l . e) = Suc (len l)"

text ‹Theorems generated by the function definition›
thm len.simps

term "len (∅ . (0::nat) . 1)"

text ‹Evaluation through ML code generation›
value "len (∅ . (0::nat) . 1)"

fun prepend :: "'a ⇒ 'a seq ⇒ 'a seq" (infixr "<<" 60)
where
  "e << ∅ = ∅ . e"
| "e << (l . a) = (e << l) . a"

term "(0::nat) << 1 << ∅"
value "(0::nat) << 1 << ∅"

text ‹Proof of a theorem using induction›
lemma "len (e << l) = len (l . e)"
proof (induction l) print_cases
  case Empty
    from prepend.simps(1) have "e << ∅ = ∅ . e" .
    thus ?case by simp
next
  case (Append l' a) print_facts
    from prepend.simps(2) have "e << (l' . a) = (e << l') . a" .
    hence "len (e << (l' . a)) = len ((e << l') . a)" by simp
    also from len.simps(2) have "... = Suc (len (e << l'))" .
    finally have 1:"len (e << (l' . a)) = Suc (len (e << l'))" .
    from len.simps(2) have "len ((l' . a) . e) = Suc (len (l' . a))" .
    with Append.IH have "... = Suc (len (e << l'))" by simp
    with 1 have "len (e << (l' . a)) = len ((l' . a) . e)" by simp
    thus ?case .
qed

lemma "len (e << l) = len (l . e)"
apply (induction l)
apply simp
apply simp
done

lemma "len (e << l) = len (l . e)"
by (induction l, simp+)

section ‹Manual proof of totalness and termination of a function›
text ‹
  For some complex recursive definitions, the automated proof of
  totalness and termination performed by "fun" may fail.
  In that case, we can use "function" and make the proofs manually.
  Here is an example on the "len" function defined above, that we redefine
  here with manual proofs.
›
function len2 :: "'a seq ⇒ nat"
where
  "len2 ∅ = 0"
| "len2 (l . e) = Suc (len2 l)"
― ‹Function is total: 1) the patterns do not overlap and cover all possible terms›
proof -
― ‹Coverage: a sequence is either empty of the result of append (theorem seq.exhaust)›
  show ‹⋀P x. (x = ∅ ⟹ P) ⟹ (⋀l e. x = l . e ⟹ P) ⟹ P› by (rule seq.exhaust)
― ‹There is only one way to match the first equation›
  show ‹∅ = ∅ ⟹ 0 = 0› by simp
― ‹There is no overlap between the two equations›
  show ‹⋀l e. ∅ = l . e ⟹ 0 = Suc (len2_sumC l)› by simp
― ‹There is only one way to match the second equation›
  show ‹⋀l e la ea. l . e = la . ea ⟹ Suc (len2_sumC l) = Suc (len2_sumC la)› by simp
qed
― ‹2) recursion terminates›
termination
proof
― ‹"size" is a function that gives the size of a term, it is defined for seq by the datatype declaration›
― ‹"measure" builds a well founded relation from a function 'a => nat, using the fact that "<" is well founded›
  let ?R = ‹measure size›
― ‹We have to show that this relation is well founded›
  show ‹wf ?R› using wf_measure by simp
― ‹and that the terms involved in the recursive definition are in the relation›
  show ‹⋀l e. (l, l . e) ∈ ?R›  by simp
qed

end

Définition d'un prédicat inductif

InductiveExample.thy

theory InductiveExample

imports Main

begin

text ‹
  Definition of even numbers by a function.
›
fun isEvenFun :: "nat ⇒ bool"
where
  "isEvenFun 0 = True"
| "isEvenFun (Suc n) = (¬ (isEvenFun n))"

value "isEvenFun 0"
value "isEvenFun 1"
value "isEvenFun 2"

text ‹
  Definition of even numbers by an inductive predicate.
›
inductive isEvenPred :: "nat ⇒ bool"
where
  "isEvenPred 0"
| "isEvenPred n ⟹ isEvenPred (Suc (Suc n))"

text ‹
  Add some facts to the set of elimination and introduction rules
  to make proof automation more efficient.
›
thm "isEvenPred.intros"
lemmas isEvenPred.intros[intro]

thm "isEvenPred.cases"
lemmas isEvenPred.cases[elim]

text ‹
  Check proof automation on simple theorems
›
lemma "isEvenPred 0" ..

lemma "¬isEvenPred (Suc 0)" by auto

lemma "isEvenPred (Suc (Suc 0))" by auto

text ‹
  Show the equivalence of the function and the predicate.
  A preliminary lemma showing that the predicate alternates with Suc is useful for this. 
›
lemma evenPred_alt: "isEvenPred (Suc n) = (¬isEvenPred n)"
  by (induction n, blast+)

lemma "isEvenFun n = isEvenPred n"
proof (induction n)
  case 0
    thus ?case by (simp add: isEvenPred.intros(1))
next
  case (Suc n)
    thus ?case by (simp add: evenPred_alt)
qed

end