Monday, January 04, 2010

Using Coroutines to go from Imperative to Functional

I really enjoyed Steve Sinclair's discussion of creating a functional interface to the GLUT UI Library. The approach he takes is to setup a coroutine between the GLUT library and the Scheme system he's developing. It's a great example of hiding the ugly details of a library behind a nice interface. In this case, ugly part is the traditional callback based state handling of GLUT, and the clean interface is a lazy infinite stream of events.

So here you can see that the GLUT callbacks are simply used to grab events, and put them on the event-list, which is then processed in parallel by the main program. Co-routines are sort of like threads that must explicitly yield to each other, but their state is maintained within themselves, not globally. Only a tiny bit of global information is needed to pass continuations back and forth. In this way, GLUT sort of takes a back seat to the main program, which from its point of view remains “purely” functional. It's nice how this technique lets you invert the way GLUT usually takes over and becomes the main driver for your program, and instead flips it over and turns it into something that your main program requests events from. This idea of turning push into pull and vice-versa seems to be a common theme in functional programming.

It's an excellent read, and shows how a bunch of concepts like coroutines and lazy streams, can be leveraged in real-life programming. I hope he has chance to continue to flesh this out further.

Hmmm, I wonder if the model he has setup would grown into a world style programming environment? Seems like that it might be a nice interface to sit on top of the lazy streams he has constructed.


  1. Standard I/O is also a case of coroutining: the OS is event-driven, but it doesn't impose that model on programmers, who see a lazy infinite stream of input values and write to a lazy infinite costream of output values.

    It's much nicer to call getchar() or (read-char) than to be called back with a buffer of stuff when a disk or network connection fills up the buffer.

  2. John -

    That's an excellent point - thanks for sharing the example!