Chapter 6. Example: A Bit of Animation

I would like to present a very simple example of animation in this chapter that makes use of higher-order functions. Please click here for a quick demo of this example.

Intuitively, animation can be performed by calling the following function animate:

// extern fun sleep(ms: int): void extern fun animate(fwork: cfun(void)): void // (* ****** ****** *) // implement animate(fwork) = { val () = fwork() val () = sleep(N(*ms*)) val () = animate(fwork) } //

The argument fwork is supposed to be called to generate some effect (for instance, outputing text on a webpage), and the function call sleep(N) pauses program execution for N milliseconds, where N is fixed constant.

Clearly, calling sleep prevents programs from being executed concurrently. Instead, let us combine sleep and animate into one function of the name sleep_animate:

// extern fun sleep_animate (ms: int, fwork: cfun(void)): void // (* ****** ****** *) // implement animate(fwork) = { val () = fwork() val () = sleep_animate(N(*ms*), fwork) } //

What sleep_animate(N, fwork) does is to schedule a call to animate on fwork after N milliseconds. Note that a call to sleep_animate should return immediately, causing no pause of program execution.

Let us generalize sleep_animate to the following function execute_after:

// extern fun execute_after (fwork: cfun(void), ms: int): void // (* ****** ****** *) // implement sleep_animate(ms, fwork) = execute_after(lam() => animate(fwork), ms) //

Given a thunk fwork (that is, a closure-function returning void) and an integer ms, execute_after schedules a call to fwork after ms milliseconds.

If we target JS, then the function execute_after can be implemented as follows:

// implement execute_after (fwork, ms) = ( // $extfcall (void, "setTimeout", cloref2fun0(fwork), ms) // ) (* end of [execute_after] *) //

where the keyword $extfcall initiates a call to the native function setTimeout in JS, and the function cloref2fun0 converts a (nullary) closure-function into an envless function (that is, one with no environment).

As an example, please find the ATS source in DigitClock.dats for a digital clock directly based on animate. And please click here for a demo of the digital clock.

Given N, fwork, and ms, the following function repeat_execute_after executes the calls fwork(i) for i ranging from 0 to N-1 and then repeats:

// extern fun repeat_execute_after ( N: int, fwork: (int) -> void, ms: int) : void = "mac#" // implement repeat_execute_after ( N, fwork, ms ) = let // fun auxmain(i: int): void = if i >= N then auxmain(0) else (fwork(i); execute_after(lam() => auxmain(i+1), ms)) // in auxmain(0) end // end of [repeat_execute_after] //

For any two consecutive calls to fwork, there is a delay of ms milliseconds between them. In a case where a call to fwork draws an image, calling repeat_execute_after may create an animation effect of some sort. For example, please click here to see an animated version of the example of Sierpinkski triangle presented previously.

Please find on-line the entirety of the code used in this chapter. The mentioned URL link(s) can be found as follows: