From d428853981c31f2e449f71c193df879bd5f23b27 Mon Sep 17 00:00:00 2001 From: Sam Caldwell Date: Sat, 12 Sep 2015 22:45:49 -0400 Subject: [PATCH] Create a FAQ based on email exchanges. It's not exactly what you'd want in a FAQ, but it aggregates most of my email exchanges with Tony and will hopefully be useful when creating a more comprehensive collection of documentation. I made a small effort to edit some of the information to be more usable to a newcomer, but a lot of it is missing important context (such as having read the paper describing the Network Calculus). --- FAQ.md | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 FAQ.md diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000..7206b55 --- /dev/null +++ b/FAQ.md @@ -0,0 +1,260 @@ +# FAQ + +* How do I run a prospect program? + - `#lang prospect` collects actions (`spawn`s) from module toplevel and + uses them as boot actions for a ground-level world. The alternative + is to use a different #lang, and to call `run-ground` yourself; see an + example in prospect/examples/example-plain.rkt. + +* How do I debug a prospect pgoram? + - You can view a colored trace of a program's execution on stderr by setting the MINIMART_TRACE environment variable, e.g. + + ``` + $ MINMART_TRACE=xetpag racket foo.rkt + ``` + + shows
+ x - exceptions
+ e - events
+ t - process states (after they handle each event)
+ p - lifecycle events (spawns, crashes, and quits)
+ a - process actions
+ g - dataspace contents
+ Adding 'W' will show whole world-states too. Remove each individual + character to turn off the corresponding trace facility; the default + value of the variable is just the empty-string. + + - For a more fine-grained approach, there are several ways to print specific patches/matchers inside your program: + + ```racket + pretty-print-patch ;; (patch matcher matcher) + pretty-print-matcher ;; matchers *are* tries + patch->pretty-string + matcher->pretty-string + matcher->abstract-graph + abstract-graph->dot + matcher->dot ;; handy for visualizing the trie structure + ``` +* How do spawned processes communicate with one another? + + | Expression | Effect of resulting patch | Meaning | + | ---------- | -------------------------- | ------- | + | (assert X) | X will be asserted | claim of X | + | (retract X) | X will be retracted | remove claim | + | (sub X) | (observe X) asserted | claim interest in X | + | (unsub X) | (observe X) retracted | unsubscribe | + | (pub X) | (advertise X) asserted | claim intent to claim X (or possibility of claim) | + | (unpub X) | (advertise X) retracted | | + + Those all construct **patch** actions. Separately, there are **message** actions: + + | Expression | Effect of resulting action | Meaning | + | ---------- | -------------------------- | ------- | + | (message X) | routes X via dataspace via (observe X) assertions | subscribers to X get it | + +* What is the difference between `pub` and `assert`? + - `(pub X)` is intended to mean *advertisement* of its body, rather than assertion. + So `(assert X)` yields a patch that means "I assert X", while + `(pub X)` yields a patch that means "I assert (advertise X)", or + interpreted more freely, "I might in future assert X". + +* How do I create a process/actor? + ```racket + ;; single actor + (spawn (lambda (event state) ... (transaction state' (list action ...))) + initial-state + initial-action ...) + ;; network of actors + (spawn-world boot-action ...) + ``` + +* How do actors at different levels communicate? + - `at-meta` (the harpoon-marker from the paper) denotes "at the next level out" - + so, you might send + ```racket + (message 'hello) + (message (at-meta 'hello)) + ``` + and the former would go to your local peers, while the latter would go + to peers one level out from you. Likewise, + ```racket + (sub 'hello) + (sub 'hello #:meta-level 1) + ``` + evaluate to + ```racket + (observe 'hello) + (patch-union (observe (at-meta 'hello)) + (at-meta (observe 'hello))) + ``` + + The latter is a bit surprising-looking perhaps. It asserts **two** items: + the first says + > HERE, I am interested in assertions 'hello labelled with "OVER THERE" + + while the second says + > OVER THERE, I am interested in assertions 'hello + + The former is necessary for the local network to route events to us, and + the latter is necessary for the remote network to route events to the + local network. + + Implicit in any `sub` call with N>0 meta-level, therefore, is the + construction of a whole *chain* of subscriptions, relaying information + up in N+1 hops across N+1 boundaries between nested actors. + +* Do I need to keep track of everything a process is asserting in order to retract only what is appropriate? + - No. You can often avoid needing to remember state like this explicitly by + using wildcard retractions: + + ```racket + (list (retract `(key ,?)) + (assert `(key ,new-key-value))) + ``` + + One potential issue with this is it generates two observable events. + That is, there is a window of time when the old term has been retracted + but the new has not yet been asserted. Implicit in this is the idea that + the actions an eventhandler produces are performed **in order**, and you + can rely on that in NC. So in the example above, the retraction will + logically happen before the assertion. You can avoid this by using + `patch-seq` instead, to combine patches into a single equivalent patch: + + ```racket + (patch-seq (retract `(key ,?)) + (assert `(key ,new-key-value))) + ``` + + +* How do I get the assertions out of a patch? + - A patch consists of two matchers, added and removed + - To get assertions out of a matcher, you have to decide what sort of assertions + you are interested in, compile a pattern for those assertions, and pass that + along with the matcher to `matcher-project/set`. + - `matcher-project/set` takes a matcher and a pattern and returns a set of lists + - Say you are in interested in assertions of the shape `('posn x y)`. + * compile the pattern using ```(compile-projection `(posn ,(?!) ,(?!)))``` + * the `(?!)` is for **capturing** the matched value. Use `?` if you want to + match but don't care about the actual value. + * the lists returned by `matcher-project/set` contain the captured values in + order. + - Say we are receiving a patch p where the assertion `('posn 2 3)` was added. + - The result of + + ```racket + (matcher-project/set (patch-added p) + (compile-projection `(posn ,(?!) ,(?!)))) + ``` + would be `(set (list 2 3))`. + - If we only cared about the y position, we could instead do + + ```racket + (matcher-project/set (patch-added p) + (compile-projection `(posn ,? ,(?!)))) + ``` + and get the result `(set (list 3))`. + - `matcher-project/set/single` is like calling `set-first` on the result of + `matcher-project/set` + - `patch-project/set` uses `values` to return the result of matching a projection + against both the added and removed bits of a patch. + +* What is the distinction between `(assert X)` and `(message X)`? + - Time. An assertion is visible to anyone interested in it from when it is + asserted until when it is retracted. A message, on the other hand, is transient. + When a message is sent, it is delivered to everyone that is interested in it + **at that time**. + +* How to inject an external event (e.g. keyboard press) into the network? + - Use `send-ground-message`. + - (Note that the argument to `send-ground-message` is wrapped in a `message`, + so to send `'foo` at the ground level use `(send-ground-message 'foo)` rather than + `(send-ground-message (message 'foo))`) + +* My gui program isn't working! + - Eventspaces. Wrap your gui code with + ```racket + (parameterize ((current-eventspace (make-eventspace))) + ...) + ``` + +* I used `spawn` but the actor isn't being created. What happened? + - The only two ways to spawn a process are to (a) supply the spawn instruction in + that world's boot-actions, or (b) have some already-existing actor supply the + spawn instruction in response to some event it receives. Note that calling `spawn` + constructs a structure which is perhaps eventually interpreted by the containing + world of an actor; it doesn't really "do" anything directly. + +* Why does `patch-seq` exist? Aren't all the actions in a transition effectively `patch-seq`d together? + - Effectively, yes, that is what happens. The difference is in the + granularity of the action: when issuing *separate patch actions*, it's + possible for an observer to observe a moment *in between* the adjacent + patches, with the dataspace in an intermediate state. +

+ Patch-seq combines multiple patches into a single patch having the same + effect as the sequence of individual patches. +

+ By combining a bunch of patch actions into a single action, there is no + opportunity for a peer to observe some intermediate state. The peer only + gets to observe things-as-they-were-before-the-patch, and + things-as-they-are-after-the-patch. + +* How do I create a tiered network, such as + ``` + ground + / \ + net1 net2 + \ + net3 + ``` + - use `spawn-world`: + ```racket + #lang prospect + (spawn-world ...) + (spawn-world ... + (spawn-world ...)) + ``` + `spawn-world` expands into a regular `spawn` with an event-handler and + state corresponding to a whole VM. The arguments to spawn-world are + actions to take at boot time in the new VM. + +* What is the outcome if I do `(assert X)` and then later `(patch-seq (retract ?) assert X)`? + - if you started with the set Y of assertions, you'd go to Y + {X}, then just {X}. + +* Can a message be included in the initial actions of a process? + - At the moment they are not allowed in the implementation; + this is more restrictive than the calculus, where any action is + permitted in a boot action. +

+ If I remember right, the reason they are not allowed is to do with + atomic assignment of responsibilities at spawn time. +

+ Imagine a socket listener detects some shared state that indicates a new + socket is waiting to be accepted. It decides to spawn a process to + handle the new connection. +

+ The protocol for sockets involves maintaining shared state signalling + the willingness of each end to continue. Once such a signal is asserted, + it must be maintained continuously, because its retraction signals + disconnection. +

+ So the newly-spawned process must signal this state. If it is spawned + without the state included in its assertions, then it must assert the + state later on. But what if it fails to do so? Then it's violating it's + implicit contract with the peer - a kind of denial of service. What if + it fails to do so because it *crashes* before it has a chance to? Then + the peer will hang forever waiting for something to happen. +

+ For this reason, it is possible to spawn processes with nonempty + assertion sets. The assertions take effect atomically with the creation + of the process itself. So the spawning process can atomically "assign + responsibility" to the spawned process, giving it no opportunity to + crash before the necessary shared state has been asserted. +

+ The current implementation is problematic though. The computation of the + initial patch is being done in the context of the spawned process, which + means that if it crashes computing the initial patch, only the spawned + process is killed - the spawning process is not signalled. More thought + required. + +* Can I split a prospect program across multiple files? + - Only one module with `#lang prospect` can be used at a time.