1 Functional GUIs
In the context of a course on programming with
algebra,
How to Design Programs [2nd ed] a teacher may ask a programming novice to
solve the following problem:
Your game needs a circle that shrinks every time the player manipulates the
mouse or presses a key. Design a program that illustrates this behavior.
(require 2htdp/image) | (require 2htdp/universe) | | ; type State is Nat | | (define (main) | (big-bang | ; initial state: | 10 | [to-draw render | 220 | 220] | [on-mouse less1] | [on-key less1])) |
| (require 2htdp/image) | | | ; type State is Nat | | (define (main) | (send (new world% | [state0 10] | [to-draw render] | [width 220] | [height 220] | [on-mouse less1] | [on-key less1]) | start)) |
|
Roughly speaking,
big-bang is a state-machine. The programmer
specifies an initial state, a bunch of event handlers, and a function that
renders the current state as an image. Each event handler accepts
big-bang’s current state plus event-specific information; it
returns a new state, which
big-bang squirrels away. Here the
initial state is
10, and as
figure 1 shows,
both the mouse and the key event handler subtract
1 from the
current state, regardless of what event they process. The
to-draw
clause specifies
render as the function that expresses
big-bang’s current state as an image and that this images is
supposed to be displayed on a 220 x 220 pixels canvas.
The 2htdp/universe library compiles the student’s program
to (roughly) the code in the right column. Since Racket’s GUI API relies on
the class system, the main function creates an instance of a class
called world%,By convention, a variable with a name
ending in % stands for a class. handing along big-bang’s keyword
arguments (after some parsing) as keyword arguments to new; when
the object is created and initialized, main calls the object’s
start method.
; Nat Any* -> Nat |
; subtract 1 from the current state, |
; regardless of the event |
(define (less1 cd . other) |
(- cd 1)) |
|
; Nat -> Image |
; render cd as a red circle |
(define (render cd) |
(define r (if (>= cd 0) cd 0)) |
(circle (+ 10 (* 10 r)) "solid" "red")) |
Figure 1: Rendering and event-handling functions
The rest of this essay explains how the world% class functions. What the
interested reader has to know about the big-bang mechanics is that
while the initial state value and the to-draw clauses are
mandatory, the on-mouse and on-key clause are
optional.Another optional big-bang clause is
on-tick, which runs a handler every time the
clock ticks. If a student omits either clause, main does not
handle mouse clicks or key presses. In contrast, the to-draw
clause is mandatory and so is the specification of an initial state. The
programmer may pick any set of values as the state space; students
are expected to specify the state space in a comment, such as the one in the
2-column code sample above.