Hi,
in the process of learning Racket I‘ve started designing a small system simulator. Now I am stuck searching for an elegant way to solve the following issue.
The simulator has an environment and multiple actors. The environment is shared among the actors, ie, they can mutate the environment variables. Each actor can have private variables not accessible by other actors. Actors take interleaved steps. Let me give an example of the user input, which is a series of lists with s-expressions like this:
; initialize environment
(init-env (list ‘(define x 1) ‘(define y 100)))
; initialize actor 1
; (init-actor actor-id action-list)
(init-actor 1 (list ‘(define local y)) ‘(set! x y)))
; initialize actor 2
(init-actor 2 (list ‘(define local x) ‘(set! y 0)))
(run-simulations)
The environment steps are immediately taken, the steps of the actors are taken in interleaved fashion with (run-simulations)
. The output is the multiple possible behaviors (sequences of all bindings).
What I am struggling with is how to maintain the private state of the actors while sharing the variables of the environment. I don’t want to require unique variable names nor use hashes to store the state.
My first try was to use one namespace for the environment and one for each actor. Before taking an action of an actor, I copy the values of the environment variables (let the identifiers be the set E) into the actor namespace, and once the step is finished I copy the values of E from the actor namespace into the environment. I ignore variables not in E, ie, the private variables of the actor. That works but it is quite ugly. All the copying feels just wrong.
I am trying now to use a single namespace ns
and continuations/coroutines, but I do not manage to create a local evaluation context for the actors. When I run (eval ‘(define local y) ns)
, the variable local
is defined globally.
Would you have a suggestion how to proceed? Perhaps a completely different approach?