FrTime: A Language for Reactive Programs
#lang frtime | package: frtime |
The frtime language supports declarative construction of reactive systems in a syntax very similar to that of Racket. It extends racket.
Within DrRacket, as an alternative to using #lang frtime, you can choose FrTime from the Choose Language menu.
This reference document describes the functionality provided by the language; for details of the design and semantic model, consult the accompanying research papers:
Brown 2008 - Cooper. Integrating dataflow evaluation into a practical higher-order call-by-value language
ESOP 2006 — Cooper and Krishnamurthi. Embedding Dynamic Dataflow in a Call-by-Value Language
Brown 2004 - Cooper and Krishnamurthi. FrTime: Functional Reactive Programming in PLT Scheme
1 Primitives
procedure
(undefined? val) → boolean?
val : any/c
value
2 Defining Custom Input Signals
procedure
(event-receiver) → event?
procedure
(send-event rcvr val) → void?
rcvr : event? val : any/c
3 Signal-Processing Procedures
procedure
(derivative val) → behavior?
val : behavior?
The following forms allow importation of lifted procedures that aren’t included in the basic FrTime language.
(require (lifted module-spec proc-name ...) ...) (require (lifted:nonstrict module-spec proc-name ...) ...)
4 Fred: Functional Reactive Wrapper around GRacket
(require frtime/gui/fred) | package: frtime |
| ||
superclass: frame% | ||
|
constructor
(new ft-frame% [label label] [ [parent parent] [width width] [height height] [x x] [y y] [style style] [enabled enabled] [border border] [spacing spacing] [alignment alignment] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height] [shown shown]]) → (is-a?/c ft-frame%) label : (or/c label-string? behavior?) parent : (or/c (is-a?/c frame%) false/c) = #f width : (or/c (integer-in 0 10000) false/c) = #f height : (or/c (integer-in 0 10000) false/c) = #f x : (or/c (integer-in -10000 10000) false/c) = #f y : (or/c (integer-in -10000 10000) false/c) = #f
style :
(listof (one-of/c 'no-resize-border 'no-caption 'no-system-menu 'hide-menu-bar 'mdi-parent 'mdi-child 'toolbar-button 'float 'metal)) = null enabled : any/c = #t border : (integer-in 0 1000) = 0 spacing : (integer-in 0 1000) = 0
alignment :
(list/c (one-of/c 'left 'center 'right) (one-of/c 'top 'center 'bottom)) = '(center top) min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = #t stretchable-height : any/c = #t shown : any/c = #f The constructor arguments are as in frame%, except that shown label, enabled, stretchable-width, and stretchable-height may be time-varying.
| ||
superclass: message% | ||
|
constructor
(new ft-message% [label label] [parent parent] [ [style style] [font font] [enabled enabled] [vert-margin vert-margin] [horiz-margin horiz-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height]]) → (is-a?/c ft-message%)
label :
(or/c label-string? behavior? (is-a?/c bitmap%) (or-of/c 'app 'caution 'stop))
parent :
(or/c (is-a?/c frame%) (is-a?/c dialog%) (is-a?/c panel%) (is-a?/c pane%)) style : (listof (one-of/c 'deleted)) = null font : (is-a?/c font%) = (racket normal-control-font) enabled : (or/c any/c behavior?) = #t vert-margin : (integer-in 0 1000) = 2 horiz-margin : (integer-in 0 1000) = 2 min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = #f stretchable-height : any/c = #f The constructor arguments are the same as in message%, except that label, enabled, stretchable-width, and stretchable-height may be time-varying.
| ||
superclass: button% | ||
|
constructor
(new ft-button% [label label] [parent parent] [ [style style] [font font] [enabled enabled] [vert-margin vert-margin] [horiz-margin horiz-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height]]) → (is-a?/c ft-button%) label : (or/c label-string? behavior (is-a?/c bitmap%))
parent :
(or/c (is-a?/c frame%) (is-a?/c dialog%) (is-a?/c panel%) (is-a?/c pane%)) style : (one-of/c 'border 'deleted) = null font : (is-a?/c font%) = (racket normal-control-font) enabled : any/c = #t vert-margin : (integer-in 0 1000) = 2 horiz-margin : (integer-in 0 1000) = 2 min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = #f stretchable-height : any/c = #f The constructor arguments are the same as in message%, except that label, enabled, stretchable-width, and stretchable-height may be time-varying.
method
(send a-ft-button get-value-e) → event?
returns an event stream that yields a value whenever the user clicks the button.
| ||
superclass: check-box% | ||
|
constructor
(new ft-check-box% [label label] [parent parent] [ [style style] [value value] [font font] [enabled enabled] [vert-margin vert-margin] [horiz-margin horiz-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height] [value-set value-set]]) → (is-a?/c ft-check-box%) label : (or/c label-string? behavior? (is-a?/c bitmap%))
parent :
(or/c (is-a?/c frame%) (is-a?/c dialog%) (is-a?/c panel%) (is-a?/c pane%)) style : (listof (one-of/c 'deleted)) = null value : any/c = #f font : (is-a?/c font%) = (racket normal-control-font) enabled : any/c = #t vert-margin : (integer-in 0 1000) = 2 horiz-margin : (integer-in 0 1000) = 2 min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = #f stretchable-height : any/c = #f value-set : event? = never-e The constructor arguments are the same as in check-box%, except that label, enabled, stretchable-width, and stretchable-height may be time-varying. Also, any occurrence on value-set sets the check box’s state to that of the event value.
method
(send a-ft-check-box get-value-b) → behavior?
returns a value that always reflects the current state of the check box.
| ||
superclass: slider% | ||
|
constructor
(new ft-slider% [label label] [min-value min-value] [max-value max-value] [parent parent] [ [init-value init-value] [style style] [font font] [enabled enabled] [vert-margin vert-margin] [horiz-margin horiz-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height] [value-set value-set]]) → (is-a?/c ft-slider%) label : (or/c label-string? behavior? false/c) min-value : (integer-in -10000 10000) max-value : (integer-in -10000 10000)
parent :
(or/c (is-a?/c frame%) (is-a?/c dialog%) (is-a?/c panel%) (is-a?/c pane%)) init-value : (integer-in -10000 10000) = min-value
style :
(listof (one-of/c 'horizontal 'vertical 'plain 'vertical-label 'horizontal-label 'deleted)) = '(horizontal) font : (is-a?/c font%) = normal-control-font enabled : any/c = #t vert-margin : (integer-in 0 1000) = 2 horiz-margin : (integer-in 0 1000) = 2 min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = (memq 'horizontal style) stretchable-height : any/c = (memq 'vertical style) value-set : event? = never-e The constructor arguments are the same as in check-box%, except that label, enabled, stretchable-width, and stretchable-height may be time-varying. Also, any occurrence on value-set sets the slider’s state to that of the event value.
method
(send a-ft-slider get-value-b) → behavior?
returns a value that always reflects the current state of the slider.
| ||
superclass: text-field% | ||
|
constructor
(new ft-text-field% [label label] [parent parent] [ [init-value init-value] [style style] [font font] [enabled enabled] [vert-margin vert-margin] [horiz-margin horiz-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height] [value-set value-set]]) → (is-a?/c ft-text-field%) label : (or/c label-string? false/c)
parent :
(or/c (is-a?/c frame%) (is-a?/c dialog%) (is-a?/c panel%) (is-a?/c pane%)) init-value : string? = ""
style :
(listof (one-of/c 'single 'multiple 'hscroll 'password 'vertical-label 'horizontal-label 'deleted)) = '(single) font : (is-a?/c font%) = (racket normal-control-font) enabled : any/c = #t vert-margin : (integer-in 0 1000) = 2 horiz-margin : (integer-in 0 1000) = 2 min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = #t stretchable-height : any/c = (memq 'multiple style) value-set : event? = never-e The constructor arguments are the same as in check-box%, except that label, enabled, stretchable-width, and stretchable-height may be time-varying. Also, any occurrence on value-set sets the text field’s state to that of the event value.
method
(send a-ft-text-field get-value-b) → behavior?
returns a value that always reflects the current state of the text field.
| ||
superclass: radio-box% | ||
|
constructor
(new ft-radio-box% [label label] [choices choices] [parent parent] [ [style style] [selection selection] [font font] [enabled enabled] [vert-margin vert-margin] [horiz-margin horiz-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height] [value-set value-set]]) → (is-a?/c ft-radio-box%) label : (or/c label-string? behavior? false/c) choices : (or/c (listof label-string?) (listof (is-a?/c bitmap%)))
parent :
(or/c (is-a?/c frame%) (is-a?/c dialog%) (is-a?/c panel%) (is-a?/c pane%))
style :
(listof (one-of/c 'horizontal 'vertical 'vertical-label 'horizontal-label 'deleted)) = '(vertical) selection : exact-nonnegative-integer? = 0 font : (is-a?/c font%) = normal-control-font enabled : any/c = #t vert-margin : (integer-in 0 1000) = 2 horiz-margin : (integer-in 0 1000) = 2 min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = #f stretchable-height : any/c = #f value-set : event? = never-e The constructor arguments are the same as in check-box%, except that label, enabled, stretchable-width, and stretchable-height may be time-varying. Also, any occurrence on value-set sets the text field’s state to that of the event value.
method
(send a-ft-radio-box get-selection-b) → behavior?
returns a value that always reflects the currently selected element in the radio box.
| ||
superclass: choice% | ||
|
constructor
(new ft-choice% [label label] [choices choices] [parent parent] [ [style style] [selection selection] [font font] [enabled enabled] [vert-margin vert-margin] [horiz-margin horiz-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height] [value-set value-set]]) → (is-a?/c ft-choice%) label : (or/c label-string? false/c) choices : (listof label-string?)
parent :
(or/c (is-a?/c frame%) (is-a?/c dialog%) (is-a?/c panel%) (is-a?/c pane%))
style :
(listof (one-of/c 'horizontal-label 'vertical-label 'deleted)) = null selection : exact-nonnegative-integer? = 0 font : (is-a?/c font%) = (racket normal-control-font) enabled : any/c = #t vert-margin : (integer-in 0 1000) = 2 horiz-margin : (integer-in 0 1000) = 2 min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = #f stretchable-height : any/c = #f value-set : event? = never-e The constructor arguments are the same as in check-box%, except that label, enabled, stretchable-width, and stretchable-height may be time-varying. Also, any occurrence on value-set sets the text field’s state to that of the event value.
method
(send a-ft-choice get-selection-b) → behavior?
returns a value that always reflects the currently selected element in the choice control.
| ||
superclass: list-box% | ||
|
constructor
(new ft-list-box% [label label] [choices choices] [parent parent] [ [style style] [selection selection] [font font] [label-font label-font] [enabled enabled] [vert-margin vert-margin] [horiz-margin horiz-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height] [value-set value-set]]) → (is-a?/c ft-list-box%) label : (or/c label-string? false/c) choices : (listof label-string?)
parent :
(or/c (is-a?/c frame%) (is-a?/c dialog%) (is-a?/c panel%) (is-a?/c pane%))
style :
(listof (one-of/c 'single 'multiple 'extended 'vertical-label 'horizontal-label 'deleted)) = '(single) selection : (or/c exact-nonnegative-integer? false/c) = #f font : (is-a?/c font%) = (racket view-control-font) label-font : (is-a?/c font%) = (racket normal-control-font) enabled : any/c = #t vert-margin : (integer-in 0 1000) = 2 horiz-margin : (integer-in 0 1000) = 2 min-width : (integer-in 0 10000) = graphical-minimum-width min-height : (integer-in 0 10000) = graphical-minimum-height stretchable-width : any/c = #t stretchable-height : any/c = #t value-set : event? = never-e The constructor arguments are the same as in check-box%, except that label, enabled, stretchable-width, and stretchable-height may be time-varying. Also, any occurrence on value-set sets the text field’s state to that of the event value.
method
(send a-ft-list-box get-selection-b) → behavior?
returns a value that always reflects the primary selection in the list box.
method
(send a-ft-list-box get-selections-b) → behavior?
returns a value that always reflects the current set of selected elements in the list box.
5 Graphical Demo Programs
TODO: document the animation library itself!
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.rkt" : A collection of balls that move in circles around the mouse pointer.
"piston.rkt" : Simulation of a piston/cylinder.
"rotation.rkt" : Balls moving in circles.
"delay-mouse.rkt" : A trail of balls following the mouse.
"ball-on-string.rkt" : A ball chasing the mouse.
"pong.rkt" : 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.
"pizza.rkt" : A simple "pizza ordering" user interface based on an HtDP exercise.
"calculator.rkt" : A simple calculator interface, also based on an HtDP exercise except that the result updates continuously as the arguments and operator change.
The next three animation examples are courtesy of Robb Cutler:
"analog-clock.rkt" : An animated real-time clock. A slider adjusts the radius of the face. Click and drag to move the face around.
"growing-points.rkt" : A field of points that grow as the mouse approaches.
"needles.rkt" : A field of needles that point at the mouse.