[racket] world/universe update model (functional update redux), using the I/O monad for state
Maybe I'm being captain obvious here, or just as easily completely
missing the real point, but:
"A list of stage change instructions", particularly if each
state-change is time-stamped, seems like an _exceptionally_ natural
way to deal with music and sound.
Best case, the mechanism helps students implement functionality such
as recording and playback, undo and redo, etc.?
On Mon, Dec 12, 2011 at 2:52 PM, John Clements
<clements at brinckerhoff.org> wrote:
> The holiday season: time to grade lots of projects, and "goof off" by thinking about how those programs could better be expressed.
>
> Here's a world/universe program written by one team in my class. It uses mutation all over the place:
>
> #lang racket
>
> (require (except-in (planet clements/rsound)
> overlay
> scale)
> 2htdp/universe
> 2htdp/image)
>
> (define octave 48)
> (define volume .4)
> (define duration 22050)
>
> (define (my-draw num)
> (empty-scene 100 100))
> (define (my-key world key)
> (begin
> (cond [(equal? key "0") (set! octave 0)]
> [(equal? key "1") (set! octave 12)]
> [(equal? key "2") (set! octave 24)]
> [(equal? key "3") (set! octave 36)]
> [(equal? key "4") (set! octave 48)]
> [(equal? key "5") (set! octave 60)]
> [(equal? key "6") (set! octave 72)]
> [(equal? key "7") (set! octave 84)]
> [(equal? key "8") (set! octave 96)]
> [(or (equal? key "=") (equal? key "+")) (if (< volume 1) (set! volume (+ volume .1)) (set! volume volume))]
> [(or (equal? key "-") (equal? key "_")) (if (> volume 0) (set! volume (- volume .1)) (set! volume volume))]
> [(equal? key "z") (if (> duration 11025) (set! duration (- duration 11025)) (set! duration duration))]
> [(equal? key "x") (if (< duration 88200) (set! duration (+ duration 11025)) (set! duration duration))]
> [(equal? key "q") (play (make-tone (midi-note-num->pitch (+ 12 octave)) volume duration))]
> [(equal? key "w") (play (make-tone (midi-note-num->pitch (+ 13 octave)) volume duration))]
> [(equal? key "e") (play (make-tone (midi-note-num->pitch (+ 14 octave)) volume duration))]
> [(equal? key "r") (play (make-tone (midi-note-num->pitch (+ 15 octave)) volume duration))]
> [(equal? key "t") (play (make-tone (midi-note-num->pitch (+ 16 octave)) volume duration))]
> [(equal? key "y") (play (make-tone (midi-note-num->pitch (+ 17 octave)) volume duration))]
> [(equal? key "u") (play (make-tone (midi-note-num->pitch (+ 18 octave)) volume duration))]
> [(equal? key "i") (play (make-tone (midi-note-num->pitch (+ 19 octave)) volume duration))]
> [(equal? key "o") (play (make-tone (midi-note-num->pitch (+ 20 octave)) volume duration))]
> [(equal? key "p") (play (make-tone (midi-note-num->pitch (+ 21 octave)) volume duration))]
> [(equal? key "[") (play (make-tone (midi-note-num->pitch (+ 22 octave)) volume duration))]
> [(equal? key "]") (play (make-tone (midi-note-num->pitch (+ 23 octave)) volume duration))]
> [(equal? key "a") (play c-hi-hat-1)]
> [(equal? key "s") (play c-hi-hat-2)]
> [(equal? key "d") (play o-hi-hat)]
> [(equal? key "f") (play snare)]
> [(equal? key "g") (play bassdrum)]
> [(equal? key "h") (play bassdrum)]
> [(equal? key "j") (play bassdrum-synth)]
> [(equal? key "k") (play clap-1)]
> [(equal? key "l") (play clap-2)]
> [(equal? key ";") (play crash-cymbal)]
> [else #f])
> 0))
> (big-bang 0
> (to-draw my-draw)
> (on-key my-key))
>
>
> Standard functional update observation:
>
> This is definitely the natural way to write the program: certain keypresses correspond to certain changes in the state of the world, and the rest stays the same.
>
> New part?
>
> What if a world function could produce a list of "state change instructions"; something like (list (change world-volume 54) (change octave 34)). The caller of world can interpret this state change as a functional update. I see this as having an advantage over functional update in that the world doesn't require an explicit reference, and there's no chaining for multiple updates.
>
> Random connection:
>
> It occurs to me that this is essentially using the I/O monad for state. That is, evaluation of the function gets a single world to work with, and is unable to update it, but can produce a list of changes to be applied when the function returns.
>
>
> Thanks for letting me ramble,
>
> John
>
>
>
> _________________________________________________
> For list-related administrative tasks:
> http://lists.racket-lang.org/listinfo/users