[racket] Advice: simulating stateful API in functional setting

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Fri Jul 15 15:17:13 EDT 2011

On Fri, Jul 15, 2011 at 2:56 PM, Stephen Bloch <sbloch at adelphi.edu> wrote:
> Last Monday I attended Dan Garcia's workshop on BYOB.  He kept pointing out (presumably for the benefit of Emmanuel
> and me) that it really is a functional language.  And yes, it has "map", "filter", "foldl", and "lambda"... but most of the
> examples and assignments one normally does in BYOB use very stateful turtle graphics.  So naturally I thought "Could I
> simulate this in universe?"
> I defined a sprite struct (with an icon, a location, a direction, a pen, etc.) and a world struct (with a list of sprites and a
> picture), and wrote a bunch of low-level operations on these that would obviously be needed.  So far so good.  I'm imagining
> that student code might say something like
>        ; zigzag : sprite -> sprite
>        (define (zigzag sprite)
>                (move 10 (rotate-cw 45 (move 10 (rotate-ccw sprite)))))
>        ...
>        (define this-sprite (make-sprite (bitmap "sprite-icon.png") (make-posn 0 0) 0 ... zigzag)
>        ...
>        (run-byob-world (list this-sprite that-sprite third-sprite) initial-background-picture)
> which would in turn call big-bang with a prewritten draw handler and a tick handler that calls each sprite's action on it.
> The problem is that some sprite actions (most obviously, "move" when you're in pen-down mode) affect not only the sprite
> itself but the world's picture.  So far the least-bad solution I've come up with is to hide a mutation of that picture inside the
> otherwise-functional "move" function.

Why is affecting the sprite "functional" and affecting the picture
"imperative"?  Any part of a program can be mutated imperatively, and
likewise any part of a program can be passed around functionally.  If
you need to modify the picture, why not pass around the picture as
part of the world?  (Or at least enough information about changes to
the picture to reconstruct it as needed.)

> I've experimented with a couple of ways to do that.  One way is to define (in my code, not visible to student code) a box
> named "world-pic", which is set-box!ed in "move" and "run-byob-world".  Another is to use just a plain variable and "set!",
> again hidden inside "move" and "run-byob-world".  Both seem to work for my toy examples so far; is there any advantage of
> one over the other?  What subtle gotchas am I going to run into?  Is "a little bit of mutation" like "a little bit pregnant?"
> Stephen Bloch
> sbloch at adelphi.edu

Posted on the users mailing list.