Funcons-beta : Storing.cbs | PRETTY | PDF
Storing
[
Datatype locations Alias locs
Type stores
Entity store
Funcon initialise-storing
Funcon store-clear
Datatype variables Alias vars
Funcon variable Alias var
Funcon allocate-variable Alias alloc
Funcon recycle-variables Alias recycle
Funcon initialise-variable Alias init
Funcon allocate-initialised-variable Alias alloc-init
Funcon assign
Funcon assigned
Funcon current-value
Funcon un-assign
Funcon structural-assign
Funcon structural-assigned
]
Meta-variables
T, T′ <: values
Stores
A storage location is represented by an atom.
The domain of a store is the set of currently allocated locations.
Mapping a location to ( )
models the absence of its stored value;
removing it from the store allows it to be re-allocated.
Entity
< _ , store(_:stores) > ---> < _ , store(_:stores) >
The current store is a mutable entity.
A transition < X , store(Sigma) > ---> < X′ , store(Sigma′) >
models
a step from X
to X′
where the difference between Sigma
and Sigma′
(if any) corresponds to storage effects.
Funcon
store-clear : =>null-type
Rule
< store-clear , store(_) > ---> < null-value , store(map( )) >
store-clear
ensures the store is empty.
Funcon
initialise-storing(X:=>T) : =>T
~> sequential(store-clear,
initialise-giving(initialise-generating(X)))
Alias
init-storing = initialise-storing
initialise-storing(X)
ensures that the entities used by the funcons for
storing are properly initialised.
Simple variables
Simple variables may store primitive or structured values. The type of
values stored by a variable is fixed when it is allocated. For instance,
allocate-variable(integers)
allocates a simple integer variable, and
allocate-variable(vectors(integers))
allocates a structured variable for
storing vectors of integers, which can be updated only monolithically.
Datatype
variables ::= variable(_:locations, _:value-types)
Alias
vars = variables
Alias
var = variable
variables
is the type of simple variables that can store values of
a particular type.
variable(L, T)
constructs a simple variable for storing values of
type T
at location L
. Variables at different locations are independent.
Note that variables
is a subtype of datatype-values
.
Funcon
allocate-variable(T:types) : =>variables
Alias
alloc = allocate-variable
allocate-variable(T)
gives a simple variable whose location is not in the
current store. Subsequent uses of allocate-variable(T′)
give independent
variables, except after recycle-variables(V,...)
or store-clear
.
Rule
< use-atom-not-in(dom(Sigma)) , store(Sigma) > ---> < L , store(Sigma′) >
map-override({L |-> ( )}, Sigma′) ~> Sigma′′
-------------------------------------------------------------------------
< allocate-variable(T:types) , store(Sigma) >
---> < variable(L, T) , store(Sigma′′) >
Funcon
recycle-variables(_:variables+) : =>null-type
Alias
recycle = recycle-variables
recycle-variables(Var,...)
removes the locations of Var
, …, from the
current store, so that they may subsequently be re-allocated.
Rule
is-in-set(L, dom(Sigma)) == true
---------------------------------------------------------------------
< recycle-variables(variable(L:locations, T:types)) , store(Sigma) >
---> < null-value , store(map-delete(Sigma, {L})) >
Rule
is-in-set(L, dom(Sigma)) == false
---------------------------------------------------------------------
< recycle-variables(variable(L:locations, T:types)) , store(Sigma) >
---> < fail , store(Sigma) >
Rule
recycle-variables(Var:variables, Var+:variables+)
~> sequential(recycle-variables(Var), recycle-variables(Var+))
Funcon
initialise-variable(_:variables, _:values) : =>null-type
Alias
init = initialise-variable
initialise-variable(Var, Val)
assigns Val
as the initial value of Var
,
and gives null-value
. If Var
already has an assigned value, it fails.
Rule
and(is-in-set(L, dom(Sigma)),
not is-value(map-lookup(Sigma, L)),
is-in-type(Val, T))
== true
----------------------------------------------------------------------------
< initialise-variable(variable(L:locations, T:types), Val:values) ,
store(Sigma) > ---> < null-value , store(map-override({L|->Val}, Sigma)) >
Rule
and(is-in-set(L, dom(Sigma)),
not is-value(map-lookup(Sigma, L)),
is-in-type(Val, T))
== false
----------------------------------------------------------------------------
< initialise-variable(variable(L:locations, T:types), Val:values) ,
store(Sigma) > ---> < fail , store(Sigma) >
Funcon
allocate-initialised-variable(T, Val:T) : =>variables
~> give(allocate-variable(T),
sequential(initialise-variable(given, Val), given))
Alias
alloc-init = allocate-initialised-variable
allocate-initialised-variable(T, Val)
allocates a simple variable for
storing values of type T
, initialises its value to Val
, and returns the
variable.
assign(Var, Val)
assigns the value Val
to the variable Var
,
provided that Var
was allocated with a type that contains Val
.
Rule
and(is-in-set(L, dom(Sigma)), is-in-type(Val, T)) == true
-----------------------------------------------------------------------
< assign(variable(L:locations, T:types), Val:values) ,
store(Sigma) > ---> < null-value , store(map-override({L|->Val}, Sigma)) >
Rule
and(is-in-set(L, dom(Sigma)), is-in-type(Val, T)) == false
--------------------------------------------------------------------------
< assign(variable(L:locations,T:types), Val:values) ,
store(Sigma) > ---> < fail , store(Sigma) >
assigned(Var)
gives the value assigned to the variable Var
,
failing if no value is currently assigned.
Rule
map-lookup(Sigma, L) ~> (Val:values)
------------------------------------------------------------------
< assigned(variable(L:locations, T:types)) , store(Sigma) >
---> < Val , store(Sigma) >
Rule
map-lookup(Sigma, L) == ( )
------------------------------------------------------------------
< assigned(variable(L:locations, T:types)) , store(Sigma) >
---> < fail , store(Sigma) >
current-value(V)
gives the same result as assigned(V)
when V
is a
simple variable, and otherwise gives V
.
It represents implicit dereferencing of a value that might be a variable.
Rule
current-value(Var:variables) ~> assigned(Var)
Rule
current-value(U:~variables) ~> U
un-assign(Var)
remove the value assigned to the variable Var
.
Rule
is-in-set(L, dom(Sigma)) == true
--------------------------------------------------------------------------
< un-assign(variable(L:locations, T:types)) , store(Sigma) >
---> < null-value , store(map-override({L |-> ( )}, Sigma)) >
Rule
is-in-set(L, dom(Sigma)) == false
--------------------------------------------------------------------------
< un-assign(variable(L:locations, T:types)) , store(Sigma) >
---> < fail , store(Sigma) >
Structured variables
Structured variables are structured values where some components are simple variables. Such component variables can be selected using the same funcons as for selecting components of structured values.
Structured variables containing both simple variables and values correspond to hybrid structures where particular components are mutable.
All datatypes (except for abstractions) can be used to form structured variables. So can maps, but not sets or multisets.
Structural generalisations of assign(Var, Val)
and
assigned(Var)
access all the simple variables contained in a
structured variable. Assignment requires each component value of a hybrid
structured variable to be equal to the corresponding component of the
structured value.
structural-assign(V1, V2)
takes a (potentially) structured variable
V1
and a (potentially) structured value V2
. Provided that the structure
and all non-variable values in V1
match the structure and corresponding
values of V2
, all the simple variables in V1
are assigned the
corresponding values of V2
; otherwise the assignment fails.
Rule
structural-assign(V1:variables, V2:values)
~> assign(V1, V2)
Rule
V1 : ~(variables)
V1 ~> datatype-value(I1:identifiers, V1*:values*)
V2 ~> datatype-value(I2:identifiers, V2*:values*)
-----------------------------------------------------------------------
structural-assign(V1:datatype-values, V2:datatype-values)
~> sequential(
check-true(is-equal(I1, I2)),
effect(tuple(interleave-map(
structural-assign(tuple-elements(given)),
tuple-zip(tuple(V1*), tuple(V2*))))),
null-value)
Note that simple variables are datatype values.
Rule
dom(M1) == {}
------------------------------------------------------
structural-assign(M1:maps(_,_), M2:maps(_,_))
~> check-true(is-equal(dom(M2), { }))
Rule
some-element(dom(M1)) ~> K
----------------------------------------------------------------------------
structural-assign(M1:maps(_, _), M2:maps(_, _))
~> sequential(check-true(is-in-set(K, dom(M2))),
structural-assign(map-lookup(M1, K), map-lookup(M2, K)),
structural-assign(map-delete(M1, {K}), map-delete(M2, {K})))
Rule
V1 : ~(datatype-values|maps(_, _))
---------------------------------------------------------------
structural-assign(V1:values,V2:values)
~> check-true(is-equal(V1, V2))
structural-assigned(V)
takes a (potentially) structured variable V
,
and computes the value of V
with all simple variables in V
replaced by
their assigned values, failing if any of them do not have assigned values.
When V
is just a simple variable or a (possibly structured) value with no
component variables, structural-assigned(V)
gives the same result as
current-value(V)
.
Rule
structural-assigned(Var:variables) ~> assigned(Var)
Rule
V : ~(variables)
V ~> datatype-value(I:identifiers, V*:values*)
----------------------------------------------------------------------------
structural-assigned(V:datatype-values)
~> datatype-value(I, interleave-map(structural-assigned(given), V*))
Note that simple variables are datatype values.
Rule
structural-assigned(M:maps(_, _))
~> map(interleave-map(structural-assigned(given), map-elements(M)))
Rule
U : ~(datatype-values|maps(_, _))
------------------------------------------
structural-assigned(U:values) ~> U