[isabelle-dev] HOLCF lists

Christian Sternagel c-sterna at jaist.ac.jp
Tue Jul 17 11:04:43 CEST 2012

Dear all,

I put together some functions on lists (that I use in some small proof) 
in Data_List.thy. While doing so and thinking about functions and proofs 
I would need in the future, I stumbled across the following points:

1) how to name HOLCF functions for which similar functions already exist 
in HOL. As you can see from my example thy-file, I tried to be as close 
to Haskell as possible and therefore hid existing HOL-names. My thinking 
was that when having a HOLCF type of lazy lists one would never want to 
use the HOL datatype list again. Maybe this was oversimplified. What do 
you think?

2) I think at some point something like "set :: 'a list => 'a set" for 
HOLCF lists would be useful... however, I did not manage to define it, 
since I was not able to prove continuity for the following specification

"set $ Nil = {}" |
"set $ (Cons$x$xs) = insert$x$(set$xs)"

Maybe such a function is not a good idea at all in the HOLCF setting and 
we should find something different.

3) also if properties only hold for "defined" instances of lists (there 
are some differences in how defined they have to be... only xs not 
bottom, or additional no element of xs is bottom, ...), I am currently 
missing a convenient way of expressing this... (first I was thinking 
about "set" from above... but then again, if "set" is a continuous 
function also "set$xs" can be undefined... so maybe there is a nicer way?)

4) How to nicely integrate natural numbers? I don't really want to mix 
=> and ->, e.g., the "list"-function "take" should have type "nat lift 
-> 'a list -> 'a list" (or something similar), rather than "nat => 'a 
list -> 'a list" I guess.

I am sure some of you have already considered the above points ;), so 
please let me know your conclusions.


-------------- next part --------------
theory Type_Classes
imports HOLCF

class eq =
  fixes eq :: "'a::pcpo \<rightarrow> 'a \<rightarrow> tr"
  assumes equals_strict [simp]:
    "eq\<cdot>x\<cdot>\<bottom> = \<bottom>" "eq\<cdot>\<bottom>\<cdot>y = \<bottom>"
    and eq_simps [dest]:
    "eq\<cdot>x\<cdot>y = TT \<Longrightarrow> x = y"
    "eq\<cdot>x\<cdot>y = FF \<Longrightarrow> x \<noteq> y"

instantiation lift :: (type) eq
definition eq_lift where
  "eq_lift \<equiv> \<Lambda> x y.
  (case x of Def x' \<Rightarrow>
    (case y of Def y' \<Rightarrow>
      Def (x' = y')
    | \<bottom> \<Rightarrow> \<bottom>)
  | \<bottom> \<Rightarrow> \<bottom>)"

lemma 1: "eq\<cdot>(x::'a lift)\<cdot>\<bottom> = \<bottom>"
  by (cases x) (simp add: eq_lift_def)+

lemma 2: "eq\<cdot>\<bottom>\<cdot>(y::'a lift) = \<bottom>"
  by (cases y) (simp add: eq_lift_def)+

lemma 3: "eq\<cdot>(x::'a lift)\<cdot>y = TT \<Longrightarrow> x = y"
  by (cases x) (cases y, simp_all add: eq_lift_def)+

lemma 4: "eq\<cdot>(x::'a lift)\<cdot>y = FF \<Longrightarrow> x \<noteq> y"
  by (cases x) (cases y, simp_all add: eq_lift_def)+

  by (intro_classes) (fact 1 2 3 4)+

-------------- next part --------------
theory Data_List
imports Type_Classes

subsection {* Setup *}

hide_type (open) list
hide_const (open) List.append List.Cons List.filter List.foldr List.map List.Nil List.take
no_notation Map.map_add (infixl "++" 100)

domain 'a list =
  Nil |
  Cons (lazy head :: 'a) (lazy tail :: "'a list")

abbreviation null :: "'a list \<rightarrow> tr" where "null \<equiv> is_Nil"

subsection {* Definitions *}

fixrec map :: "('a \<rightarrow> 'b) \<rightarrow> 'a list \<rightarrow> 'b list" where
  "map\<cdot>f\<cdot>Nil = Nil" |
  "map\<cdot>f\<cdot>(Cons\<cdot>x\<cdot>xs) = Cons\<cdot>(f\<cdot>x)\<cdot>(map\<cdot>f\<cdot>xs)"

fixrec filter :: "('a \<rightarrow> tr) \<rightarrow> 'a list \<rightarrow> 'a list" where
  "filter\<cdot>P\<cdot>Nil = Nil" |
  "filter\<cdot>P\<cdot>(Cons\<cdot>x\<cdot>xs) =
    If (P\<cdot>x) then Cons\<cdot>x\<cdot>(filter\<cdot>P\<cdot>xs) else filter\<cdot>P\<cdot>xs"

fixrec iterate :: "('a \<rightarrow> 'a) \<rightarrow> 'a \<rightarrow> 'a list" where
  "iterate\<cdot>f\<cdot>x = Cons\<cdot>x\<cdot>(iterate\<cdot>f\<cdot>(f\<cdot>x))"

fixrec foldr :: "('a \<rightarrow> 'b \<rightarrow> 'b) \<rightarrow> 'b \<rightarrow> 'a list \<rightarrow> 'b" where
  "foldr\<cdot>f\<cdot>d\<cdot>Nil = d" |
  "foldr\<cdot>f\<cdot>d\<cdot>(Cons\<cdot>x\<cdot>xs) = f\<cdot>x\<cdot>(foldr\<cdot>f\<cdot>d\<cdot>xs)"

fixrec elem :: "'a::{domain, eq} \<rightarrow> 'a list \<rightarrow> tr" where
  "elem\<cdot>x\<cdot>Nil = FF" |
  "elem\<cdot>x\<cdot>(Cons\<cdot>y\<cdot>ys) = (eq\<cdot>x\<cdot>y orelse elem\<cdot>x\<cdot>ys)"

fixrec append :: "'a list \<rightarrow> 'a list \<rightarrow> 'a list" where
  "append\<cdot>Nil\<cdot>ys = ys" |
  "append\<cdot>(Cons\<cdot>x\<cdot>xs)\<cdot>ys = Cons\<cdot>x\<cdot>(append\<cdot>xs\<cdot>ys)"

fixrec all :: "('a \<rightarrow> tr) \<rightarrow> 'a list \<rightarrow> tr" where
  "all\<cdot>P\<cdot>Nil = TT" |
  "all\<cdot>P\<cdot>(Cons\<cdot>x\<cdot>xs) = (P\<cdot>x andalso all\<cdot>P\<cdot>xs)"

abbreviation append_syn :: "'a list \<Rightarrow> 'a list \<Rightarrow> 'a list" (infixr "++" 65) where
  "xs ++ ys \<equiv> append\<cdot>xs\<cdot>ys"

lemma filter_strict [simp]:
  "filter\<cdot>P\<cdot>\<bottom> = \<bottom>"
  by fixrec_simp

lemma map_strict [simp]:
  "map\<cdot>f\<cdot>\<bottom> = \<bottom>"
  by fixrec_simp

lemma map_ID [simp]:
  "map\<cdot>ID\<cdot>xs = xs"
  by (induct xs) simp_all

lemma strict_foldr_strict2 [simp]:
  "(\<And>x. f\<cdot>x\<cdot>\<bottom> = \<bottom>) \<Longrightarrow> foldr\<cdot>f\<cdot>\<bottom>\<cdot>xs = \<bottom>"
  by (induct xs, auto) fixrec_simp

lemma foldr_strict [simp]:
  "foldr\<cdot>f\<cdot>d\<cdot>\<bottom> = \<bottom>"
  "foldr\<cdot>f\<cdot>\<bottom>\<cdot>Nil = \<bottom>"
  "foldr\<cdot>\<bottom>\<cdot>d\<cdot>(Cons\<cdot>x\<cdot>xs) = \<bottom>"
  by fixrec_simp+

lemma elem_strict [simp]:
  "elem\<cdot>x\<cdot>\<bottom> = \<bottom>"
  "elem\<cdot>\<bottom>\<cdot>(Cons\<cdot>y\<cdot>ys) = \<bottom>"
  by fixrec_simp+

lemma append_strict1 [simp]:
  "\<bottom> ++ ys = \<bottom>"
  by fixrec_simp

lemma append_Nil2 [simp]:
  "xs ++ Nil = xs"
  by (induct xs) simp_all

lemma append_assoc [simp]:
  "(xs ++ ys) ++ zs = xs ++ ys ++ zs"
  by (induct xs) simp_all

lemma filter_append [simp]:
  "filter\<cdot>P\<cdot>(xs ++ ys) = filter\<cdot>P\<cdot>xs ++ filter\<cdot>P\<cdot>ys"
proof (induct xs)
  case (Cons x xs) thus ?case by (cases "P\<cdot>x") (auto simp: If_and_if)
qed simp_all

(*FIXME: move*)
lemma orelse_assoc [simp]:
  "((x orelse y) orelse z) = (x orelse y orelse z)"
  by (cases x rule: trE) auto

lemma elem_append [simp]:
  "elem\<cdot>x\<cdot>(xs ++ ys) = (elem\<cdot>x\<cdot>xs orelse elem\<cdot>x\<cdot>ys)"
    by (induct xs) auto

lemma filter_filter [simp]:
  "filter\<cdot>P\<cdot>(filter\<cdot>Q\<cdot>xs) = filter\<cdot>(\<Lambda> x. Q\<cdot>x andalso P\<cdot>x)\<cdot>xs"
  by (induct xs) (auto simp: If2_def [symmetric] split: split_If2)

(*FIXME: move*)
lemma neg_orelse [simp]: "neg\<cdot>(x orelse y) = (neg\<cdot>x andalso neg\<cdot>y)"
  by (cases x rule: trE) auto

(*FIXME: move*)
lemma neg_andalso [simp]: "neg\<cdot>(x andalso y) = (neg\<cdot>x orelse neg\<cdot>y)"
  by (cases x rule: trE) auto

lemma head_append [simp]:
  "head\<cdot>(xs ++ ys) = If null\<cdot>xs then head\<cdot>ys else head\<cdot>xs"
  by (cases xs) simp_all


More information about the isabelle-dev mailing list