[Haskell-cafe] Animated line art
Paul Johnson
paul at cogito.org.uk
Sat Dec 6 12:05:00 EST 2008
Andrew Coppin wrote:
> So I want some sort of sequencing primitives.
Sequencing generally suggests a monad. something = do { action1; delay
10; action2}
> I had a go at writing what I thought the interface might look like.
> (Fortunately, I made no attempt to *implement* it - otherwise I would
> doubtless have wasted huge amounts of time implementing something that
> isn't designed right yet!) Unfortunately Haskell doesn't really
> provide a way to write an "interface", and then write the
> implementation behind it seperately somewhere else. So the "code" I
> wrote wasn't actually compilable at all, but it was useful to sketch
> something out.
When I do this I generally write functions like foo = error "foo: Not
implemented yet"
> My initial idea was that I could have some kind of monad for
> controlling adding and removing stuff. The monad could provide an
> "add" action that adds a visual object to the frame and returns a
> unique ID. Then you could have a "remove" action that removes the
> specified ID again. And a "wait" action that makes the display stay
> the same for so many seconds. (But the visual objects may internally
> be animated.)
I'd suggest that each object has its own action to animate it. You will
need to write a custom monad to interleave actions. See
http://www.cs.chalmers.se/~koen/pubs/jfp99-monad.ps for something along
the right lines.
> Then I hit upon the idea that maybe one thread of control could
> "spawn" a second one - so that for example one thread could generate a
> bunch of snowflakes raining down the screen while a seperate thread
> rotates a geometric figure in the center. Or something.
Sounds right.
> Of course, these "threads" have no need (or use) for actually running
> concurrently - they are only "concurrent" in the sence that they both
> affect the same frame, rather than their actions happening one after
> another on consecutive frames.
>
> Next I got to thinking that maybe these threads of control might need
> to communicate for synchronisation. E.g., when a rotating line reaches
> 90° with another line, a signal is sent to another thread, which then
> adds another visual element or stops the animation or something. The
> parent thread *could* algebraicly _compute_ what time this will
> happen, but sending a signal is much simpler. (E.g., if you change the
> speed of an animation, the threads still stay synchronised without you
> having to remember to adjust parameters in your calculations all over
> the place...)
Yup. I did exactly this, albeit for a very different application.
Unfortunately the code belongs to my employer so I can't post it. But
if you look at the paper above and also read about the "ContT" monad you
will get the right idea. Its a bit mind-bending, but you suspend a
thread by getting its continuation (using callCC) and stuffing it into
whatever data structure is being used to hold pending threads (e.g. a
semaphore queue).
Or you could use the existing concurrent threads mechanism, which is
kludgier but less work.
> There's still one little problem though. The "threads of control" are
> for sequencing stuff. They are inherantly discrete; *add* this thing,
> *remove* this other thing, *send* this signal, *wait* to receive a
> signal, etc. But something like, say, rotating a line, is inherantly
> continuous. So there's a discrete system for sequencing stuff - which
> I seem to have worked out fairly well - and there also needs to be a
> continuous system for doing all the things with are smooth functions
> of time.
Thats where Reactive stuff comes in.
>
> So maybe the continuous stuff should just be a type alias to a regular
> Haskell function? Ah, but wait... I said I might want to send a signal
> when an animation reaches a specific stage, right? So these
> "functions" need to do more than just map time to some other variable;
> they need to be able to send signals. And hey, actually, what are the
> chances of a time sample exactly lining up with the instant that the
> notable event occurs? How do I want to handle that?
Events are part of reactive frameworks.
Paul.
More information about the Haskell-Cafe
mailing list