Files
IBAFLang/IBAF-cbs/Funcons-beta/Computations/Normal/Storing/Storing.cbs
2023-11-01 09:29:33 +01:00

347 lines
11 KiB
Plaintext

### 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
Type
locations ~> atoms
Alias
locs = locations
/*
A storage location is represented by an atom.
*/
Type
stores ~> maps(locations, values?)
/*
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.
*/
Funcon
assign(_:variables, _:values) : =>null-type
/*
`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) >
Funcon
assigned(_:variables) : =>values
/*
`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) >
Funcon
current-value(_:values) : =>values
/*
`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
Funcon
un-assign(_:variables) : =>null-type
/*
`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.
*/
Funcon
structural-assign(_:values, _:values) : =>null-type
/*
`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))
Funcon
structural-assigned(_:values) : =>values
/*
`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