Theory Fresh_Class

section ‹Fresh monad operations as class operations›

theory Fresh_Class
imports
  Fresh_Monad
  Name
begin

text ‹
  The @{const fresh} locale allows arbitrary instantiations. However, this may be inconvenient to
  use. The following class serves as a global instantiation that can be used without interpretation.
  The arb› parameter of the locale redirects to @{const default}.

  Some instantiations are provided. For @{typ name}s, underscores are appended to generate a fresh
  name.
›

class fresh = linorder + default +
  fixes "next" :: "'a  'a"
  assumes next_ge: "next x > x"

global_interpretation Fresh_Monad.fresh "next" default
  defines fresh_create = create
      and fresh_Next = Next
      and fresh_fNext = fNext
      and fresh_frun = frun_fresh
      and fresh_run = run_fresh
proof
  show "x < next x" for x by (rule next_ge)
qed

lemma [code]: "fresh_frun m S = fst (run_state m (fresh_fNext S))"
by (simp add: fresh_fNext_def fresh_frun_def)

lemma [code]: "fresh_run m S = fst (run_state m (fresh_Next S))"
by (simp add: fresh_Next_def fresh_run_def)

instantiation nat :: fresh begin

definition default_nat :: nat where
"default_nat = 0"

definition next_nat where
"next_nat = Suc"

instance
by intro_classes (auto simp: next_nat_def)

end

instantiation char :: default
begin

definition default_char :: char where
"default_char = CHR ''_''"

instance ..

end

instantiation name :: fresh begin

definition default_name where
"default_name = Name ''_''"

definition next_name where
"next_name xs = Name.append xs default"

instance proof
  fix v :: name
  show "v < next v"
    unfolding next_name_def default_name_def
    by (rule name_append_less) simp
qed

end

primrec fresh_list :: nat  'a :: fresh set  'a list where
fresh_list 0 _ = [] |
fresh_list (Suc n) A = Next A # fresh_list n (insert (Next A) A)

lemma fresh_list_length[simp]: length (fresh_list n A) = n
  by (induction n arbitrary: A) auto

context
  fixes A :: 'a :: fresh set
  assumes finite: finite A
begin

lemma fresh_list_fresh: set (fresh_list n A)  A = {}
  using finite
  by (induction n arbitrary: A) (auto simp: Next_not_member)

lemma fresh_list_fresh_elem: x  set (fresh_list n A)  x  A
  using fresh_list_fresh by auto

lemma fresh_list_distinct: distinct (fresh_list n A)
using finite proof (induction n arbitrary: A)
  case (Suc n)
  then have Next A  set (fresh_list n (insert (Next A) A))
    by (meson Fresh_Class.fresh_list_fresh_elem finite.insertI insertI1)
  then show ?case
    using Suc by auto
qed simp

end

export_code
  fresh_create fresh_Next fresh_fNext fresh_frun fresh_run fresh_list
  checking Scala? SML?

end