_The Father Time Language (FrTime)_ The `frtime' collection contains the implementation of FrTime, a language that supports declarative construction of reactive systems through signals, or time-varying values. Signals are classified as either behaviors, which have a value at any point in (conceptually continuous) time, or events, which are streams of discrete occurrences. Unlike (for example) boxes, the time-varying nature of signals propagates automatically to expressions in which they are used. To interact with FrTime, set the language level to FrTime. You can also make FrTime the language for a module: (module (lib "frtime.ss" "frtime") ) For the animation library and demo programs, set the language level to (module ...), open the file, and execute. The demos are perhaps the best way to learn about FrTime. Note that FrTime is experimental, and various aspects of it may change significantly, though we will try our best to maintain backwards compatibility. _Primitive Signals_ > seconds : behavior[num] This behavior updates approximately every second with the value of (current-seconds). > milliseconds : behavior[num] This behavior updates approximately every 20 milliseconds with the value of (current-milliseconds). Future versions of FrTime will provide an interface through which the programmer can create timers with arbitrary update frequencies. _Creating New Signals_ > (new-cell [behavior]) -> cell (a special behavior) The returned cell can be used as a behavior; initially its value is determined by the optional behavior given to the constructor (default is ). For example, (new-cell seconds) behaves like _seconds_. > (set-cell! cell behavior) -> void This procedure changes the value of the cell to that of the new behavior. > (event-receiver) -> event-rcvr (a special event source) The returned value can be used as an event source. Specifically, it emits an event occurrence whenever it is used as the first argument to the following procedure: > (send-event event-rcvr any) -> void Emits the second argument as an occurrence on the given event source. _Signal Processors_ > (value-now behavior[a]) -> a This procedure projects the current value of the given behavior. > (delay-by behavior[a] behavior[num]) -> behavior[a] This procedure delays the given behavior by the given number of milliseconds (which need not be constant). > (integral behavior[num] {behavior[num] = 20}) -> behavior[num] Computes a numeric approximation of the integral of the first argument with respect to time, at a minimum rate given by the second argument (interpreted in milliseconds). This procedure will probably be rewritten soon. > (derivative behavior[num]) -> behavior[num] Computes a numeric approximation of the derivative of the first argument with respect to time. This procedure needs to be rewritten. > (map-e proc event) -> event > (event . ==> . proc) -> event Returns an event source isomorphic to the given one, except that each occurrence is the result of applying the given procedure to the input event occurrence. > (filter-e pred event) -> event > (event . =#> . pred) -> event Returns a filtered version of the given event source. Only occurrences that satisfy the given predicate survive. > (merge-e event ...) -> event Merges all of the input event sources into a single event source. > (once-e event) -> event Returns an event source that carries only the first occurrence of the argument event source. (The rest are filtered out.) > (changes behavior) -> event Returns an event source which occurs each time the argument behavior changes. The value of the occurrence is the behavior's new value. > (hold event [init]) -> behavior Constructs a behavior from a given initial value (defaults to ) and an event source. The value of the behavior is the value of the most recent event occurrence. > (switch behavior event[behavior]) -> behavior Returns a behavior that "switches" each time the argument event occurs. > (accum-e event[a -> a] a) -> event[a] Constructs an event source by accumulating changes (carried by the given event source) over an initial value. > (accum-b event[a -> a] a) -> behavior[a] Combines functionality of accum-e and hold to construct a behavior. (accum-b ev init) = (hold init (accum-e ev init)). > (collect-e event[a] b (a b -> b)) -> event[b] Like accum-e, except the transformer function is fixed and is applied to the current accumulator and the event occurrence. > (collect-b event[a] b (a b -> b)) -> behavior[b] collect-b : collect-e :: accum-b : accum-e > (when-e behavior) -> event The returned event source carries an occurrence each time the argument behavior changes from false to true (non-false). > ( behavior ...) -> behavior FrTime provides "lifted" versions of most of MzScheme. This means that these procedures may be applied to behaviors, and the result automatically recomputes whenever any of the arguments changes. _Special Syntax for FrTime_ > (if boolean-behavior then-expr else-expr) SYNTAX FrTime permits the use of behaviors in conditional statements. By definition, if the condition is , then the result is also . Otherwise, the expression reflects the branch currently selected by the condition. FrTime also provides 'cond', 'and', 'or', and 'case'. > (snapshot (var ...) expr) SYNTAX This projects the current values of the named variables within the given expression. > (require (lifted module-spec proc-name ...) ...) SYNTAX > (require (lifted:nonstrict module-spec proc-name ...) ...) SYNTAX > (require (as-is module-spec proc-name ...) ...) SYNTAX > (require (as-is:unchecked module-spec proc-name ...) ...) SYNTAX FrTime provides several new 'require' forms, which can be used to import optionally modified definitions from existing libraries. The 'lifted' form takes a module specification and names of any number of primitive procedures. The imported versions of the primitives can be applied to behaviors. The 'lifted:nonstrict' form is similar, except that, when given arguments, FrTime will still perform the application, instead of simply forcing the output value to be . The 'as-is' forms do not lift imported procedures, so these should not generally be used with signals. The 'unchecked' version permits application to signals, while the plain 'as-is' always reports an error if the user attempts to apply to a signal. _Graphical Demo Programs_ To run the following animation/GUI demos, simply set the language level to FrTime, open the corresponding file, and Execute. See the demo source code for more information. orbit-mouse.ss : A collection of balls that move in circles around the mouse pointer. piston.ss : Simulation of a piston/cylinder. rotation.ss : Balls moving in circles. delay-mouse.ss : A trail of balls following the mouse. ball-on-string.ss : A ball chasing the mouse. pong.ss : A simple pong/air-hockey game. The left paddle moves with numeric keypad; the right paddle moves with the mouse. The 'r' key resets the score. net-pong-*.ss : A networked version of the pong/air-hockey game. Currently known to work under Linux. To play, open the client on one machine and the server on another. Execute both (and require if necessary, depending on language level). Evaluate (self) on each. Results will be something like: [client] > (self) #3(tid 128.148.38.2:1180 main) and [server] > (self) #3(tid 128.148.33.71:1178 main) Now tell each machine about the other: [client] > (set-cell! server (make-tid '128.148.33.71 1178 'frtime-heart)) [server] > (set-cell! client (make-tid '128.148.38.2 1180 'frtime-heart)) Note the differences between the #3(tid ...) output and the (make-tid ...) commands---there is no colon (:) between the host and port, and main becomes 'frtime-heart. After setting the cells, complete the connection by clicking the left mouse button in both animation windows. The player running the server can reset the score by pressing 'r'. pizza.ss : A simple "pizza ordering" user interface based on an HtDP exercise. calculator.ss : A simple calculator interface, also based on an HtDP exercise except that the result updates continuously as the arguments and operator change. Robb Cutler's Examples analog-clock.ss : An animated real-time clock. A slider adjusts the radius of the face. Click and drag to move the face around. growing-points.ss : A field of points that grow as the mouse approaches. needles.ss : A field of needles that point at the mouse.