text‹Clean (pronounced as: ``C lean'' or ``Céline'' [selin]) is a minimalistic imperative language
C-like control-flow operators based on a shallow embedding into the ``State Exception Monads'' theory
in 🍋‹MonadSE.thy›. It strives for a type-safe notation of program-variables, an
construction of the typed state-space in order to facilitate incremental verification
open-world extensibility to new type definitions intertwined with the program
.
comprises:
begin{itemize}
item C-like control flow with term‹break› and term‹return›,
item global variables,
item function calls (seen as monadic executions) with side-effects, recursion
and local variables,
item parameters are modeled via functional abstractions
(functions are monads); a passing of parameters to local variables
might be added later,
item direct recursive function calls,
item cartouche syntax for ‹λ›-lifted update operations supporting global and local variables.
end{itemize}
section‹A High-level Description of the Clean Memory Model›
subsection‹A Simple Typed Memory Model of Clean: An Introduction › text‹ Clean is based on a ``no-frills'' state-exception monad 🪙‹type_synonym ('o, 'σ) MONSE = ‹'σ ⇀ ('o × 'σ)›› with the
definitions of term‹bind› and term‹unit›.
this language, sequence operators, conditionals and loops can be integrated. ›
text‹From a concrete program, the underlying state 🪙‹'σ› is 🪙‹incrementally› constructed by a
of extensible record definitions: 🪙 Initially, an internal control state is defined to give semantics to term‹break› and term‹return› statements: \begin{isar}
record control_state = break_val :: bool return_val :: bool \end{isar} 🪙‹control_state› represents the $\sigma_0$ state. 🪙 Any global variable definition block with definitions $a_1 : \tau_1$ $\dots$ $a_n : \tau_n$
is translated into a record extension: \begin{isar}
record σ$_{n+1}$ = σ$_n$ + a$_1$ :: $\tau_1$; ...; $a_n$ :: $\tau_n$ \end{isar} 🪙 Any local variable definition block (as part of a procedure declaration)
with definitions $a_1 : \tau_1$ $\dots$ $a_n : \tau_n$ is translated into the record extension: \begin{isar}
record σ$_{n+1}$ = σ$_n$ + a$_1$ :: $\tau_1$ list; ...; $a_n$ :: $\tau_n$ list; result :: $\tau_{result-type}$ list; \end{isar}
where the 🍋‹_ list›-lifting is used to model a 🪙‹stack› of local variable instances
in case of direct recursions and the term‹result_value› used for the value of the term‹return›
statement.›
text‹ The 🪙‹record› package creates an 🪙‹'σ› extensible record type 🪙‹'σ control_state_ext› where the 🪙‹'σ› stands for extensions that are subsequently ``stuffed'' in
. Furthermore, it generates definitions for the constructor, accessor and update functions and
derives a number of theorems over them (e.g., ``updates on different fields commute'',
`accessors on a record are surjective'', ``accessors yield the value of the last update''). The
of these theorems constitutes the 🪙‹memory model› of Clean, providing an incrementally
state-space for global and local program variables. In contrast to axiomatizations
memory models, our generated state-spaces might be ``wrong'' in the sense that they do not
the operational behaviour of a particular compiler or a sufficiently large portion of the
language; however, it is by construction 🪙‹logically consistent› since it is
to derive falsity from the entire set of conservative extension schemes used in their
. A particular advantage of the incremental state-space construction is that it
incremental verification and interleaving of program definitions with theory development.›
subsection‹ Formally Modeling Control-States ›
text‹The control state is the ``root'' of all extensions for local and global variable
in Clean. It contains just the information of the current control-flow: a term‹break› occurred
meaning all commands till the end of the control block will be skipped) or a term‹return› occurred
meaning all commands till the end of the current function body will be skipped).›
record control_state =
break_status :: bool
return_status :: bool
(* ML level representation: *)
ML‹ val t = @{term "σ ( break_status := False )"}›
(* break quits innermost while or for, return quits an entire execution sequence. *) definition break :: "(unit, ('σ_ext) control_state_ext) MONSE" where"break ≡ (λ σ. Some((), σ ( break_status := True )))"
text‹ On the basis of the control-state, assignments, conditionals and loops are reformulated
into term‹break›-aware and term‹return›-aware versions as shown in the definitions of term‹assign› and term‹if_C› (in this theory file, see below). ›
text‹For Reasoning over Clean programs, we need the notion of independance of an
update from the control-block: ›
definition control_independence :: "(('b==>'b)==>'a control_state_scheme ==> 'a control_state_scheme) ==> bool" (‹♯›) where"♯ upd ≡ (∀σ T b. break_status (upd T σ) = break_status σ ∧ return_status (upd T σ) = return_status σ ∧ upd T (σ( return_status := b )) = (upd T σ)( return_status := b ) ∧ upd T (σ( break_status := b )) = (upd T σ)( break_status := b )) "
lemma strong_vs_weak_ci : "♯! L ==>♯ (λf. λσ. lens_put L σ (f (lens_get L σ)))" unfolding strong_control_independence_def control_independence_def by (simp add: break_statusL_def lens_indep_def return_statusL_def upd2put_def createL_def)
lemma expimnt :"♯! (createL getv updv) ==> (λf σ. updv (λ_. f (getv σ)) σ) = updv" unfolding createL_def strong_control_independence_def
break_statusL_def return_statusL_def lens_indep_def apply(rule ext, rule ext) apply auto unfolding upd2put_def (* seems to be independent *) oops
lemma expimnt : "vwb_lens (createL getv updv) ==> (λf σ. updv (λ_. f (getv σ)) σ) = updv" unfolding createL_def strong_control_independence_def lens_indep_def
break_statusL_def return_statusL_def vwb_lens_def apply(rule ext, rule ext) apply auto unfolding upd2put_def wb_lens_def weak_lens_def wb_lens_axioms_def mwb_lens_def
mwb_lens_axioms_def apply auto (* seems to be independent *) oops
lemma strong_vs_weak_upd : assumes * : "♯! (createL getv updv)"(* getv and upd are constructed as lense *) and ** : "(λf σ. updv (λ_. f (getv σ)) σ) = updv"(* getv and upd are involutive *) shows"♯ (updv)" apply(insert * **) unfolding createL_def upd2put_def by(drule strong_vs_weak_ci, auto)
text‹This quite tricky proof establishes the fact that the special case ‹hd(getv σ) = []› for ‹getv σ = []› is finally irrelevant in our setting.
This implies that we don't need the list-lense-construction (so far).› lemma strong_vs_weak_upd_list : assumes * : "♯! (createL (getv:: 'b control_state_scheme ==> 'c list) (updv:: ('c list ==> 'c list) ==> 'b control_state_scheme ==> 'b control_state_scheme))" (* getv and upd are constructed as lense *) and ** : "(λf σ. updv (λ_. f (getv σ)) σ) = updv"(* getv and upd are involutive *) shows"♯ (updv ∘ upd_hd)" proof - have *** : "♯! (createL (hd ∘ getv ) (updv ∘ upd_hd))" using * ** by (simp add: indep_list_lift strong_control_independence_def) show"♯ (updv ∘ upd_hd)" apply(rule strong_vs_weak_upd) apply(rule ***) apply(rule ext, rule ext, simp) apply(subst (2) **[symmetric]) proof - fix f:: "'c ==> 'c"fix σ :: "'b control_state_scheme" show"updv (upd_hd (λ_. f (hd (getv σ)))) σ = updv (λ_. upd_hd f (getv σ)) σ" proof (cases "getv σ") case Nil thenshow ?thesis by (simp,metis (no_types) "**" upd_hd.simps(1)) next case (Cons a list) thenshow ?thesis proof - have"(λc. f (hd (getv σ))) = ((λc. f a)::'c ==> 'c)" usinglocal.Cons by auto thenshow ?thesis by (metis (no_types) "**"local.Cons upd_hd.simps(2)) qed qed qed qed
lemma exec_stop_vs_control_independence [simp]: "♯ upd ==> exec_stop (upd f σ) = exec_stop σ" unfolding control_independence_def exec_stop_def by simp
lemma exec_stop_vs_control_independence' [simp]: "♯ upd ==> (upd f (σ ( return_status := b ))) = (upd f σ)( return_status := b )" unfolding control_independence_def exec_stop_def by simp
lemma exec_stop_vs_control_independence'' [simp]: "♯ upd ==> (upd f (σ ( break_status := b ))) = (upd f σ) ( break_status := b )" unfolding control_independence_def exec_stop_def by simp
subsection‹An Example for Global Variable Declarations.› text‹We present the above definition of the incremental construction of the state-space in more
via an example construction.
a global variable ‹A› representing an array of integer. This 🪙‹global variable declaration› corresponds to the effect of the following
declaration:
🪙‹record state0 = control_state + A :: "int list"›
is later extended by another global variable, say, ‹B› representing a real
in the Cauchy Sequence form @{typ "nat ==> (int × int)"} as follows:
further extension would be needed if a (potentially recursive) function ‹f› with some local ‹tmp› is defined: 🪙‹record state2 = state1 + tmp :: "nat stack" result_value :: "nat stack" ›, where the ‹stack›
for modeling recursive instances is just a synonym for ‹list›. ›
subsection‹ The Assignment Operations (embedded in State-Exception Monad) › text‹Based on the global variable states, we define term‹break›-aware and term‹return›-aware
of the assignment. The trick to do this in a generic 🪙‹and› type-safe way is to provide
generated accessor and update functions (the ``lens'' representing this global variable,
. cite‹"Foster2009BidirectionalPL" and "DBLP:journals/toplas/FosterGMPS07" and
DBLP:conf/ictac/FosterZW16"›) to the generic assign operators. This pair of accessor and update
all relevant semantic and type information of this particular variable and 🪙‹characterizes›
variable semantically. Specific syntactic support~🪙‹via the Isabelle concept of
: 🪙‹https://isabelle.in.tum.de/doc/isar-ref.pdf›› will hide away the syntactic overhead
permit a human-readable form of assignments or expressions accessing the underlying state. ›
text‹An update of the variable ‹A› based on the state of the previous example is done
@{term [source = true] ‹assign_global A_upd (λσ. list_update (A σ) (i) (A σ ! j))›} ‹A[i] = A[j]›; arbitrary nested updates can be constructed accordingly.›
text‹Local variable spaces work analogously; except that they are represented by a stack
order to support individual instances in case of function recursion. This requires
generation of specific push- and pop operations used to model the effect of
or leaving a function block (to be discussed later).›
text‹Semantically, the difference between 🪙‹global› and 🪙‹local› is rather unimpressive as the
following lemma shows. However, the distinction matters for the pretty-printing setup of Clean.› lemma"(upd :==L rhs) = ((upd ∘ upd_hd) :==G rhs)" unfolding assign_local_def assign_global_def by simp
text‹The ‹return› command in C-like languages is represented basically by an assignment to a local ‹result_value› (see below in the Clean-package generation), plus some setup of term‹return_status›. Note that a term‹return› may appear after a term‹break› and should have no effect
this case.›
definition returnC0 where"returnC0 A = (λσ. if exec_stop σ then Some((), σ) else (A ;- set_return_status) σ)"
subsection‹Example for a Local Variable Space› text‹Consider the usual operation ‹swap› defined in some free-style syntax as follows:
{cartouche [display] ‹
function_spec swap (i::nat,j::nat)
local_vars tmp :: int
defines " ‹ tmp := A ! i› ;- ‹ A[i] := A ! j› ;- ‹ A[j] := tmp› "›} ›
text‹
the fantasy syntax ‹tmp := A ! i›, we can construct the following semantic code:
{term [source = true] ‹assign_local tmp_update (λσ. (A σ) ! i )›} where ‹tmp_update› is the
operation generated by the 🪙‹record›-package, which is generated while treating local variables ‹swap›. By the way, a stack for ‹return›-values is also generated in order to give semantics
a ‹return› operation: it is syntactically equivalent to the assignment of
result variable in the local state (stack). It sets the term‹return_val› flag.
management of the local state space requires function-specific ‹push› and ‹pop› operations,
which suitable definitions are generated as well:
definition pop_local_swap_state :: "(unit,'a local_swap_state_scheme) MONSE"
where "pop_local_swap_state σ =
Some(hd(local_swap_state.result_value σ),
σ(local_swap_state.tmp:= tl( local_swap_state.tmp σ) ))"›} ‹result_value› is the stack for potential result values (not needed in the concrete ‹swap›). ›
section‹ Global and Local State Management via Extensible Records ›
text‹In the sequel, we present the automation of the state-management as schematically discussed
the previous section; the declarations of global and local variable blocks are constructed by
extensions of @{typ "'a control_state_scheme"}, defined above.›
ML‹
optionT t = Type(@{type_name "Option.option"},[t]);
MON_SE_T res state = state --> optionT(HOLogic.mk_prodT(res,state));
merge_control_stateS (@{typ "('a)control_state_scheme"},t) = t
|merge_control_stateS (t, @{typ "('a)control_state_scheme"}) = t
|merge_control_stateS (t, t') = if (t = t') then t else error"can not merge Clean state"
var_kind = global_var of typ | local_var of typ
type_of(global_var t) = t | type_of(local_var t) = t
state_field_tab = var_kind Symtab.table
Data = Generic_Data
type T = (state_field_tab * typ (* current extensible record *))
val empty = (Symtab.empty,control_stateS)
val extend = I fun merge((s1,t1),(s2,t2)) = (Symtab.merge (op =)(s1,s2),merge_control_stateS(t1,t2))
);
val get_data = Data.get o Context.Proof;
val map_data = Data.map;
val get_data_global = Data.get o Context.Theory;
val map_data_global = Context.theory_map o map_data;
val get_state_type = snd o get_data
val get_state_type_global = snd o get_data_global
val get_state_field_tab = fst o get_data
val get_state_field_tab_global = fst o get_data_global fun upd_state_type f = map_data (fn (tab,t) => (tab, f t)) fun upd_state_type_global f = map_data_global (fn (tab,t) => (tab, f t))
fun fetch_state_field (ln,X) = let val a::b:: _ = rev (Long_Name.explode ln) in ((b,a),X) end;
fun filter_name name ln = let val ((a,b),X) = fetch_state_field ln inif a = name then SOME((a,b),X) else NONE end;
fun filter_attr_of name thy = let val tabs = get_state_field_tab_global thy in map_filter (filter_name name) (Symtab.dest tabs) end;
fun is_program_variable name thy = Symtab.defined((fst o get_data_global) thy) name
fun is_global_program_variable name thy = case Symtab.lookup((fst o get_data_global) thy) name of
SOME(global_var _) => true
| _ => false
fun is_local_program_variable name thy = case Symtab.lookup((fst o get_data_global) thy) name of
SOME(local_var _) => true
| _ => false
fun declare_state_variable_global f field thy = let val Const(name,ty) = Syntax.read_term_global thy field in (map_data_global (apfst (Symtab.update_new(name,f ty))) (thy)
handle Symtab.DUP _ => error("multiple declaration of global var")) end;
fun declare_state_variable_local f field ctxt = let val Const(name,ty) = Syntax.read_term_global (Context.theory_of ctxt) field in (map_data (apfst (Symtab.update_new(name,f ty)))(ctxt)
handle Symtab.DUP _ => error("multiple declaration of global var")) end;
text‹In the following, we add a number of advanced HOL-term constructors in the style of
{ML_structure "HOLogic"} from the Isabelle/HOL libraries. They incorporate the construction
types during term construction in a bottom-up manner. Consequently, the leafs of such
should always be typed, and anonymous loose-@{ML "Bound"} variables avoided.›
ML‹
(* HOLogic extended *)
fun mk_None ty = let val none = 🍋‹Option.option.None›
val none_ty = ty --> Type(🍋‹option›,[ty]) in Const(none, none_ty) end;
fun mk_Some t = let val some = 🍋‹Option.option.Some›
val ty = fastype_of t
val some_ty = ty --> Type(🍋‹option›,[ty]) in Const(some, some_ty) $ t end;
fun dest_listTy (Type(🍋‹List.list›, [T])) = T;
fun is_listTy t = case t of (Type(🍋‹List.list›, [T])) => true
| _ => false
fun mk_hdT t = let val ty = fastype_of t in Const(🍋‹List.hd›, ty --> (dest_listTy ty)) $ t end
fun mk_tlT t = let val ty = fastype_of t in Const(🍋‹List.tl›, ty --> ty) $ t end
fun mk_undefined (@{typ"unit"}) = Const (🍋‹Product_Type.Unity›, 🍋‹unit›)
|mk_undefined t = Const (🍋‹HOL.undefined›, t)
fun meta_eq_const T = Const (🍋‹Pure.eq›, T --> T --> propT);
fun mk_meta_eq (t, u) = meta_eq_const (fastype_of t) $ t $ u;
fun mk_pat_tupleabs [] t = t
| mk_pat_tupleabs [(s,ty)] t = absfree(s,ty)(t)
| mk_pat_tupleabs ((s,ty)::R) t = HOLogic.mk_case_prod(absfree(s,ty)(mk_pat_tupleabs R t)) fun mk_pat_tupleabs_wrapper [] t = absfree("unitparam",@{typ unit}) t
| mk_pat_tupleabs_wrapper R t = mk_pat_tupleabs R t
fun read_constname ctxt n = fst(dest_Const(Syntax.read_term ctxt n))
fun wfrecT order recs = let val funT = domain_type (fastype_of recs)
val aTy = domain_type funT
val ordTy = HOLogic.mk_setT(HOLogic.mk_prodT (aTy,aTy)) in Const(🍋‹Wfrec.wfrec›, ordTy --> (funT --> funT) --> funT) $ order $ recs end
fun mk_lens_type from_ty to_ty = Type(@{type_name "lens.lens_ext"},
[from_ty, to_ty, HOLogic.unitT]);
›
text‹And here comes the core of the 🪙‹Clean›-State-Management: the module that provides the
functionality for the commands keywords 🪙‹global_vars›, 🪙‹local_vars›and🪙‹local_vars_test›. Note that the difference between 🪙‹local_vars›and🪙‹local_vars_test›is just a technical one: 🪙‹local_vars› can only be used inside a Clean functionspecification, made with the 🪙‹function_spec›
command. On the other hand, 🪙‹local_vars_test›is defined as a global Isar command for test purposes.
A particular feature of the local-variable management is the provision of definitions forterm‹push› andterm‹pop› operations --- encoded as 🍋‹('o, 'σ) MONSE› operations --- which are vital for
the function specifications defined below. ›
funtyp_2_string_raw(Type(s,[TFree_]))=ifString.isSuffix"_scheme"s thenLong_Name.base_name(unsuffix"_scheme"s) elseLong_Name.base_name(unsuffix"_ext"s) |typ_2_string_raw(Type(s,_))= error("Illegalparameterizedstatetype-notallowedinClean:"^s) |typ_2_string_raw_=error"Illegalstatetype-notallowedinClean." funnew_state_record0add_record_cmdis_global_kind(aS,raw_fields)thy= letvalstate_index=(Int.toStringolengthoSymtab.dest) (StateMgt_core.get_state_field_tab_globalthy)
val state_pos = (Binding.pos_of o #1 o hd) raw_fields (*This hd is probably the reason why we cant have empty local vars*)
val ((raw_params, binding), res_ty) = case aS of
SOME d => d
| NONE => (([], Binding.make(state_index,state_pos)), NONE)
val binding = if is_global_kind then mk_global_state_name binding
else mk_local_state_name binding
val raw_parent = SOME(typ_2_string_raw (StateMgt_core.get_state_type_global thy))
val pos = Binding.pos_of binding fun upd_state_typ thy = StateMgt_core.upd_state_type_global
(K (parse_typ_'a (Proof_Context.init_global thy) binding)) thy
val result_binding = Binding.make(result_name,pos)
val raw_fields' = case res_ty of
NONE => raw_fields
| SOME res_ty => raw_fields @ [(result_binding,res_ty, NoSyn)] in thy |> add_record_cmd {overloaded = false} is_global_kind
raw_params binding raw_parent raw_fields'
|> upd_state_typ
end
val add_record_cmd = add_record_cmd0 read_fields;
val add_record_cmd' = add_record_cmd0 pair;
val new_state_record = new_state_record0 add_record_cmd
val new_state_record' = new_state_record0 add_record_cmd';
fun clean_ctxt_parser b = Parse.$$$ "("
|-- (Parse.type_args_constrained -- Parse.binding)
-- (if b then Scan.succeed NONE else Parse.typ >> SOME)
--| Parse.$$$ ")"
: (((string * string option) list * binding) * string option) parser
val _ =
Outer_Syntax.command 🍋‹global_vars› "define global state record"
(Scan.option (clean_ctxt_parser true) -- Scan.repeat1 Parse.const_binding
>> (Toplevel.theory o new_state_record true));
val _ =
Outer_Syntax.command 🍋‹local_vars_test› "define local state record"
(Scan.option (clean_ctxt_parser false) -- Scan.repeat1 Parse.const_binding
>> (Toplevel.theory o new_state_record false));
local funmk_local_accessX=Const(@{const_name"Fun.comp"},dummyT) $Const(@{const_name"List.list.hd"},dummyT)$X in funapp_sigma0(st:T)dbtm=casetmof Const(name,_)=>if#is_globalstname thentm$(Bounddb) then tm $ (Bound db) (* lambda lifting *)
else if #is_local st name then (mk_local_access tm) $ (Bound db) (* lambda lifting local *)
else tm (* no lifting *)
| Free _ => tm
| Var _ => tm
| Bound n => if n > db then Bound(n + 1) else Bound n
| Abs (x, ty, tm') => Abs(x, ty, app_sigma0 st (db+1) tm')
| t1 $ t2 => (app_sigma0 st db t1) $ (app_sigma0 st db t2)
fun app_sigma db tm = init #> (fn st => app_sigma0 st db tm)
fun scope_var st name = if #is_global st name then SOME true
else if #is_local st name then SOME false
else NONE
fun assign_update var = var ^ Record.updateN
fun transform_term0 abs scope_var tm = let fun transform t1 t2 name ty =
Const ( case scope_var name of
SOME true => @{const_name "assign_global"}
| SOME false => @{const_name "assign_local"}
| NONE => raise TERM ("mk_assign", [t1])
, dummyT)
$ Const(assign_update name, ty)
$ abs t2 in case tm of
Const ("_type_constraint_", _) $ Const (@{const_name "Clean.syntax_assign"}, _)
$ (t1 as Const ("_type_constraint_", _) $ Const (name, ty))
$ t2 => transform t1 t2 name ty
| Const (@{const_name "Clean.syntax_assign"}, _)
$ (t1 as Const ("_type_constraint_", _) $ Const (name, ty))
$ t2 => transform t1 t2 name ty
| _ => abs tm end
fun transform_term st sty =
transform_term0
(fn tm => Abs ("σ", sty, app_sigma0 st 0 tm))
(scope_var st)
fun transform_term' st = transform_term st dummyT
fun string_tr ctxt content args = letfun err () = raise TERM ("string_tr", args) in
(case args of
[(Const (@{syntax_const "_constrain"}, _)) $ (Free (s, _)) $ p] =>
(case Term_Position.decode_position1 p of
SOME {pos, ...} => Symbol_Pos.implode (content (s, pos))
|> Syntax.parse_term ctxt
|> transform_term (init ctxt) (StateMgt_core.get_state_type ctxt)
|> Syntax.check_term ctxt
| NONE => err ())
| _ => err ()) end end end ›
fun read_params params ctxt = let
val Ts = Syntax.read_typs ctxt (map snd params); in (Ts, fold Variable.declare_typ Ts ctxt) end;
fun read_result ret_ty ctxt = let val [ty] = Syntax.read_typs ctxt [ret_ty]
val ctxt' = Variable.declare_typ ty ctxt in (ty, ctxt') end
fun read_function_spec ( params, ret_type, read_variant_opt) ctxt = let val (params_Ts, ctxt') = read_params params ctxt
val (rty, ctxt'') = read_result ret_type ctxt'
val variant = case read_variant_opt of
NONE => NONE
|SOME f => SOME(f ctxt'')
val paramT_l = (map2 (fn (b, _) => fn T => (b, T)) params params_Ts) in ((paramT_l, rty, variant),ctxt'') end
fun check_absence_old term = letfun test (s,ty) = if s = @{const_name "old"} andalso fst (dest_Type ty) = "fun" then error("the old notation is not allowed here!")
else false in exists_Const test termend
fun transform_old sty term = letfun transform_old0 (Const(@{const_name "old"}, Type ("fun", [_,_])) $ term )
= (caseterm of
(Const(s,ty) $ Bound x) => (Const(s,ty) $ Bound (x+1))
| _ => error("illegal application of the old notation."))
|transform_old0 (t1 $ t2) = transform_old0 t1 $ transform_old0 t2
|transform_old0 (Abs(s,ty,term)) = Abs(s,ty,transform_old0 term)
|transform_old0 term = term in Abs("σpre", sty, transform_old0 term) end
fun define_cond binding f_sty transform_old check_absence_old cond_suffix params read_cond (ctxt:local_theory) = let val params' = map (fn(b, ty) => (Binding.name_of b,ty)) params
val src' = case transform_old (read_cond ctxt) of
Abs(nn, sty_pre, term) => mk_pat_tupleabs params' (Abs(nn,sty_pre,term))
| _ => error ("define abstraction for result" ^ Position.here 🍋)
val bdg = Binding.suffix_name cond_suffix binding
val _ = check_absence_old src'
val bdg_ty = HOLogic.mk_tupleT(map (#2) params) --> f_sty HOLogic.boolT
val eq = mk_meta_eq(Free(Binding.name_of bdg, bdg_ty),src')
val args = (SOME(bdg,NONE,NoSyn), (Binding.empty_atts,eq),[],[]) in StateMgt.cmd args ctxt end
fun define_precond binding sty =
define_cond binding (fn boolT => sty --> boolT) I check_absence_old "_pre"
fun define_body_core binding args_ty sty params body = let val params' = map (fn(b,ty) => (Binding.name_of b, ty)) params
val bdg_core = Binding.suffix_name "_core" binding
val bdg_core_name = Binding.name_of bdg_core
val umty = args_ty --> StateMgt.MON_SE_T @{typ"unit"} sty
val eq = mk_meta_eq(Free (bdg_core_name, umty),mk_pat_tupleabs params' body)
val args_core =(SOME (bdg_core, SOME umty, NoSyn), (Binding.empty_atts, eq), [], [])
in StateMgt.cmd args_core end
fun define_body_main {recursive = x:bool} binding rty sty params read_variant_opt _ ctxt = let val push_name = StateMgt.mk_push_name (StateMgt.mk_local_state_name binding)
val pop_name = StateMgt.mk_pop_name (StateMgt.mk_local_state_name binding)
val bdg_core = Binding.suffix_name "_core" binding
val bdg_core_name = Binding.name_of bdg_core
val bdg_rec_name = Binding.name_of(Binding.suffix_name "_rec" binding)
val bdg_ord_name = Binding.name_of(Binding.suffix_name "_order" binding)
val args_ty = HOLogic.mk_tupleT (map snd params)
val rmty = StateMgt_core.MON_SE_T rty sty
val umty = StateMgt.MON_SE_T @{typ"unit"} sty
val argsProdT = HOLogic.mk_prodT(args_ty,args_ty)
val argsRelSet = HOLogic.mk_setT argsProdT
val params' = map*Copyright 20182019 UniversitSaclay-, France
val measure_term = case read_variant_opt of
NONE => Free(bdg_ord_name,args_ty --> HOLogic.natT)
* modification permitted the conditions
val *
--> argsRelSet )
$ measure_term
val lhs_main = if x andalso is_none (read_variant_opt ) then Free(Binding.name_of binding, (args_ty --> HOLogic.natT)
--> args_ty rmty $
Free(bdg_ord_name, args_ty --> HOLogic.natT)
else Free(Binding.name_of binding, args_ty --> rmty)
val rhs_main = mk_pat_tupleabs params'
(Const(@{const_name "Clean.blockC"}, umty --> umty --> rmty --> rmty)
$ Const(read_constname ctxt (Binding.name_of push_name),umty)
$ (Const* APARTICULARDISCLAIMEDNO COPYRIGHT
$ HOLogic.mk_tuple (map Free params'))
$ Const(read_constname ctxt (Binding.name_of pop_name),rmty))
rhs_main_recwfrecT
(Abs(bdg_rec_name, (args_ty --> rmty) ,
mk_pat_tupleabsparams
(Const(@{const_name "Clean.blockC"}, umty-->umty->rmty
$ Const
$ (Constonstnamecore_name
(args_ty
$ (Bound
$ HOLogic.mk_tuple (map Free params'))
read_constnameof_e,y)java.lang.StringIndexOutOfBoundsException: Index 98 out of bounds for length 98
val eq_main = mk_meta_eq(lhs_main, if x then rhs_main_rec else rhs_main )
val args_main = (SOME(binding,NONE,NoSyndingtts,],] in ctxt |>"(<ga <Turnstile> ( _ ←)) σ M)" end
val _ = Local_Theory.exit_result_global;
val _ = Named_Target.theory_map_result;
val _ = Named_Target exec_assign_globalD'=exec_assign_globallobalD1
(* This code is in large parts so messy because the extensible record package (used inside StateMgt.new_state_record)isonlyavailablestransformationnglobalcontextstexts whichcutsthelocalcontextcalculationsintotwohalves.Thesecondhalvesiscut againintotwohalvesbecausetheefinitionnitionforeapparentlyoessnotkeffect eforefiningnghelockstructureenoteparated(hisproblemanperhapsvercome somehow)) Precondition:thetermsoftheread-functionsellypedinerespective localcontexts.
*) fun
error "No measure required in non-recursive call"
|checkNsem_function_spec_gen (isrec as {recursive :ool
{bindinging_type,read_variant_opts,
read_body, read_pre, read_post params} : funct_spec_sem
thy = letfixesams_Tset_tytxt
nctxt "\sigma<> ( _ \<eftarrowtarrow |> Proof_Cotex.ad_fixes (map (fnn s,ty)=>(s,SOME,NoS)) params_s) (* this declares the parameters of a function specification as Free variables overrides a possible constant declaration) and assigns the declared type to them *) |> (fn (X, ctxt) => fg params_Ts ret_ty ctxt) , ctxt) val (theory_map, thy') = Named_Target.theory_map_resultassumes "exec_stopsigma
(K (fn=ed_Targetmap
(read_function_spec params, ret_type)
#> addfixes
)
y in thy' |> theory_map let valsty_old =StateMgt_core thy
( define_precond binding sty_old params
#> define_postcondding_ty_oldd_post in parse_contract
|> StateMgt.new_state_record false<>C_def
|> theory_map
ty t letly=teMgt_core xt
pd params
_ StateMgt_coreTet_tyy
valle_k<equiv while_C" val ctxt' = if #recursive isrec then Proof_Context.add_fixes ,ME ags_ty--> mon_se_t,NSn)] ctxt |> #2 else ctxt =_ody ctx' os_t in ctxt' |> define_body_core binding args_ty sty params body end) (* separation nasty, but nec. in order to make the body definition take effect. No other reason. *) |> theoapply(ssubst Monadwhhle__E_unfold) (fn params => fn ret_ty => fn cxt => let val sty = StateMgt_cget_st_yecx then show "\C b do" val body = read_body ctxt mon_se_ty in ctxt |> define_body_main isrec binding ret_ty sty params read_variant_opt body end)java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30 nd
constsnth\<^sub>C::"'alist\<Rightarrow>'b\<Rightarrow>'a" overloadingnth\<^sub>C\<equiv>"nth\<^sub>C::'alist\<Rightarrow>nat\<Rightarrow>'a" begin definition nth\<^sub>C_nat:"nth\<^sub>C(S::'alist)(a)\<equiv>nthSa" end
overloadingnth\<^sub>C\<equiv>"nth\<^sub>C::'alist\<Rightarrow>int\<Rightarrow>'a" begin definition nth\<^sub>C_int:"nth\<^sub>C(S::'alist)(a)\<equiv>nthS(nata)" end
(* From dev-branch: don't know which version is better. bu 25.11.25 *) fun mk_return_C upd rhs = let val upd_ty = fastype_of upd
val (rty, sty) = case upd_ty of Type("fun",[Type("fun", [Type(_(*list*),[r_ty]),_]),
Type ("fun",[s_ty,_])]) => (r_ty, s_ty)
| _=>error "mk_return_C: illegal type for update func"
val rhs_ty = sty --> rty
val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty in Const(🍋‹returnC›, upd_ty --> rhs_ty --> mty) $ upd $ rhs end
(* overridden by afp version. *) fun mk_return_C upd rhs = let val ty = fastype_of rhs
val (sty,rty) = case ty of
Type("fun", [sty,rty]) => (sty,rty)
| _ => error "mk_return_C: illegal type for body"
val upd_ty = (HOLogic.listT rty --> HOLogic.listT rty) --> sty --> sty
val rhs_ty = sty --> rty
val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty in Const(🍋‹returnC›, upd_ty --> rhs_ty --> mty) $ upd $ rhs end
(* From dev-branch: don't know which version is better. bu 25.11.25 *) fun mk_assign_global_C upd rhs = let val upd_ty = fastype_of upd
val (rty, sty) = case upd_ty of Type("fun",[Type("fun", [r_ty,_]),
Type ("fun",[s_ty,_])]) => (r_ty, s_ty)
| _=>error "mk_assign_global_C: illegal type for update func"
val rhs_ty = sty --> rty
val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty in Const(🍋‹assign_global›, upd_ty --> rhs_ty --> mty) $ upd $ rhs end
(* overridden by afp version. *) fun mk_assign_global_C upd rhs = let val ty = fastype_of rhs
val (sty,rty) = case ty of
Type("fun", [sty,rty]) => (sty,rty)
| _ => error "mk_assign_global_C: illegal type for body"
val upd_ty = (rty --> rty) --> sty --> sty
val rhs_ty = sty --> rty
val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty in Const(🍋‹assign_global›, upd_ty --> rhs_ty --> mty) $ upd $ rhs end
(* From dev-branch: don't know which version is better. bu 25.11.25 *) fun mk_assign_local_C upd rhs = let val upd_ty = fastype_of upd
val (rty, sty) = case upd_ty of Type("fun",[Type("fun", [Type(_(*list*),[r_ty]),_]),
Type ("fun",[s_ty,_])]) => (r_ty, s_ty)
| _=>error "mk_assign_local_C: illegal type for update func"
val rhs_ty = sty --> rty
val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty in Const(🍋‹assign_local›, upd_ty --> rhs_ty --> mty) $ upd $ rhs end
(* overridden by afp version. *) fun mk_assign_local_C upd rhs = let val ty = fastype_of rhs
val (sty,rty) = case ty of
Type("fun", [sty,rty]) => (sty,rty)
| _ => error "mk_assign_local_C: illegal type for body"
val upd_ty = (HOLogic.listT rty --> HOLogic.listT rty) --> sty --> sty
val rhs_ty = sty --> rty
val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty in Const(🍋‹assign_local›, upd_ty --> rhs_ty --> mty) $ upd $ rhs end
fun mk_call_C opn args = let val ty = fastype_of opn
val (argty,mty) = case ty of
Type("fun", [argty,mty]) => (argty,mty)
| _ => error "mk_call_C: illegal type for body"
val sty = case mty of
Type("fun", [sty,_]) => sty
| _ => error "mk_call_C: illegal type for body 2"
val args_ty = sty --> argty in Const(🍋‹callC›, ty --> args_ty --> mty) $ opn $ args end
(* missing : a call_assign_local and a call_assign_global. Or define at HOL level ? *)
fun mk_if_C c B B' = let val ty = fastype_of B
val ty_cond = case ty of
Type("fun", [argty,_]) => argty --> HOLogic.boolT
|_ => error "mk_if_C: illegal type for body" in Const(🍋‹if_C›, ty_cond --> ty --> ty --> ty) $ c $ B $ B' end;
fun mk_while_C c B = let val ty = fastype_of B
val ty_cond = case ty of
Type("fun", [argty,_]) => argty --> HOLogic.boolT
|_ => error "mk_while_C: illegal type for body" in Const(🍋‹while_C›, ty_cond --> ty --> ty) $ c $ B end;
fun mk_while_anno_C inv f c B = (* no type-check on inv and measure f *) let val ty = fastype_of B
val (ty_cond,ty_m) = case ty of
Type("fun", [argty,_]) =>( argty --> HOLogic.boolT,
argty --> HOLogic.natT)
|_ => error "mk_while_anno_C: illegal type for body" in Const(🍋‹while_C_A›, ty_cond --> ty_m --> ty_cond --> ty --> ty)
$ inv $ f $ c $ B end;
fun mk_block_C push body pop = let val body_ty = fastype_of body
val pop_ty = fastype_of pop
val bty = body_ty --> body_ty --> pop_ty --> pop_ty in Const(🍋‹blockC›, bty) $ push $ body $ pop end
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.135Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.