Theory utp_expr_ovld

section ‹ Overloaded Expression Constructs ›

theory utp_expr_ovld
  imports utp
begin

subsection ‹ Overloadable Constants ›

text ‹ For convenience, we often want to utilise the same expression syntax for multiple constructs.
  This can be achieved using ad-hoc overloading. We create a number of polymorphic constants and then
  overload their definitions using appropriate implementations. In order for this to work,
  each collection must have its own unique type. Thus we do not use the HOL map type directly,
  but rather our own partial function type, for example. ›
  
consts
  ― ‹ Empty elements, for example empty set, nil list, 0... › 
  uempty     :: "'f"
  ― ‹ Function application, map application, list application... ›
  uapply     :: "'f  'k  'v"
  ― ‹ Function update, map update, list update... ›
  uupd       :: "'f  'k  'v  'f"
  ― ‹ Domain of maps, lists... ›
  udom       :: "'f  'a set"
  ― ‹ Range of maps, lists... ›
  uran       :: "'f  'b set"
  ― ‹ Domain restriction ›
  udomres    :: "'a set  'f  'f"
  ― ‹ Range restriction ›
  uranres    :: "'f  'b set  'f"
  ― ‹ Collection cardinality ›
  ucard      :: "'f  nat"
  ― ‹ Collection summation ›
  usums      :: "'f  'a"
  ― ‹ Construct a collection from a list of entries ›
  uentries   :: "'k set  ('k  'v)  'f"
  
text ‹ We need a function corresponding to function application in order to overload. ›
  
definition fun_apply :: "('a  'b)  ('a  'b)"
where "fun_apply f x = f x"

declare fun_apply_def [simp]

definition ffun_entries :: "'k set  ('k  'v)  ('k, 'v) ffun" where
"ffun_entries d f = graph_ffun {(k, f k) | k. k  d}"

text ‹ We then set up the overloading for a number of useful constructs for various collections. ›
  
adhoc_overloading
  uempty  0 and
  uapply  fun_apply and uapply  nth and uapply  pfun_app and
  uapply  ffun_app and
  uupd  pfun_upd and uupd  ffun_upd and uupd  list_augment and
  udom  Domain and udom  pdom and udom  fdom and udom  seq_dom and
  udom  Range and uran  pran and uran  fran and uran  set and
  udomres  pdom_res and udomres  fdom_res and
  uranres  pran_res and udomres  fran_res and
  ucard  card and ucard  pcard and ucard  length and
  usums  list_sum and usums  Sum and usums  pfun_sum and
  uentries  pfun_entries and uentries  ffun_entries

subsection ‹ Syntax Translations ›

syntax
  "_uundef"     :: "logic" (u)
  "_umap_empty" :: "logic" ([]u)
  "_uapply"     :: "('a  'b, ) uexpr  utuple_args  ('b, ) uexpr" (‹_'(_')a [999,0] 999)
  "_umaplet"    :: "[logic, logic] => umaplet" (‹_ // _›)
  ""            :: "umaplet => umaplets"             (‹_›)
  "_UMaplets"   :: "[umaplet, umaplets] => umaplets" (‹_,/ _›)
  "_UMapUpd"    :: "[logic, umaplets] => logic" (‹_/'(_')u [900,0] 900)
  "_UMap"       :: "umaplets => logic" ((1[_]u))
  "_ucard"      :: "logic  logic" (#u'(_'))
  "_udom"       :: "logic  logic" (domu'(_'))
  "_uran"       :: "logic  logic" (ranu'(_'))
  "_usum"       :: "logic  logic" (sumu'(_'))
  "_udom_res"   :: "logic  logic  logic" (infixl u 85)
  "_uran_res"   :: "logic  logic  logic" (infixl u 85)
  "_uentries"   :: "logic  logic  logic" (entru'(_,_'))

translations
  ― ‹ Pretty printing for adhoc-overloaded constructs ›
  "f(x)a"    <= "CONST uapply f x"
  "domu(f)" <= "CONST udom f"
  "ranu(f)" <= "CONST uran f"  
  "A u f" <= "CONST udomres A f"
  "f u A" <= "CONST uranres f A"
  "#u(f)" <= "CONST ucard f"
  "f(k  v)u" <= "CONST uupd f k v"
  "0" <= "CONST uempty" ― ‹ We have to do this so we don't see uempty. Is there a better way of printing? ›

  ― ‹ Overloaded construct translations ›
  "f(x,y,z,u)a" == "CONST bop CONST uapply f (x,y,z,u)u"
  "f(x,y,z)a" == "CONST bop CONST uapply f (x,y,z)u"
  "f(x,y)a"  == "CONST bop CONST uapply f (x,y)u"  
  "f(x)a"    == "CONST bop CONST uapply f x"
  "#u(xs)"  == "CONST uop CONST ucard xs"
  "sumu(A)" == "CONST uop CONST usums A"
  "domu(f)" == "CONST uop CONST udom f"
  "ranu(f)" == "CONST uop CONST uran f"
  "[]u"     => "«CONST uempty»"
  "u"     == "«CONST undefined»"
  "A u f" == "CONST bop (CONST udomres) A f"
  "f u A" == "CONST bop (CONST uranres) f A"
  "entru(d,f)" == "CONST bop CONST uentries d «f»"
  "_UMapUpd m (_UMaplets xy ms)" == "_UMapUpd (_UMapUpd m xy) ms"
  "_UMapUpd m (_umaplet  x y)"   == "CONST trop CONST uupd m x y"
  "_UMap ms"                      == "_UMapUpd []u ms"
  "_UMap (_UMaplets ms1 ms2)"     <= "_UMapUpd (_UMap ms1) ms2"
  "_UMaplets ms1 (_UMaplets ms2 ms3)" <= "_UMaplets (_UMaplets ms1 ms2) ms3"

subsection ‹ Simplifications ›

lemma ufun_apply_lit [simp]: 
  "«f»(«x»)a = «f(x)»"
  by (transfer, simp)

lemma lit_plus_appl [lit_norm]: "«(+)»(x)a(y)a = x + y" by (simp add: uexpr_defs, transfer, simp)
lemma lit_minus_appl [lit_norm]: "«(-)»(x)a(y)a = x - y" by (simp add: uexpr_defs, transfer, simp)
lemma lit_mult_appl [lit_norm]: "«times»(x)a(y)a = x * y" by (simp add: uexpr_defs, transfer, simp)
lemma lit_divide_apply [lit_norm]: "«(/)»(x)a(y)a = x / y" by (simp add: uexpr_defs, transfer, simp)

lemma pfun_entries_apply [simp]:
  "(entru(d,f) :: (('k, 'v) pfun, ) uexpr)(i)a = ((«f»(i)a)  i u d  u)"
  by (pred_auto)
    
lemma udom_uupdate_pfun [simp]:
  fixes m :: "(('k, 'v) pfun, ) uexpr"
  shows "domu(m(k  v)u) = {k}u u domu(m)"
  by (rel_auto)

lemma uapply_uupdate_pfun [simp]:
  fixes m :: "(('k, 'v) pfun, ) uexpr"
  shows "(m(k  v)u)(i)a = v  i =u k  m(i)a"
  by (rel_auto)

subsection ‹ Indexed Assignment ›

syntax
  ― ‹ Indexed assignment ›
  "_assignment_upd" :: "svid  uexp  uexp  logic" ((_[_] :=/ _) [63, 0, 0] 62)

translations
  ― ‹ Indexed assignment uses the overloaded collection update function \emph{uupd}. ›
  "_assignment_upd x k v" => "x := &x(k  v)u"

end