The Father Time Language (FrTime)

_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

To interact with FrTime, set the language level to FrTime.  You can
also make FrTime the language for a module:

(module <module-name> (lib "" "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

_Primitive Signals_

> seconds : behavior[num]

  This behavior updates approximately every second with the value of

> 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 <undefined>).  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

> (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

> (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
  <undefined>) 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

> (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).
> (<proc> 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 <undefined>, then the result is also
  <undefined>.  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 <undefined> 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. : A collection of balls that move in circles around
the mouse pointer. : Simulation of a piston/cylinder. : Balls moving in circles. : A trail of balls following the mouse. : A ball chasing the mouse. : 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:

> (self)
#3(tid main)

> (self)
#3(tid main)

Now tell each machine about the other:
> (set-cell! server (make-tid ' 1178 'frtime-heart))

> (set-cell! client (make-tid ' 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

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'. : A simple "pizza ordering" user interface based on an HtDP
exercise. : 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 : An animated real-time clock.  A slider adjusts the radius
of the face.  Click and drag to move the face around. : A field of points that grow as the mouse approaches. : A field of needles that point at the mouse.