Monday, September 29, 2008

Representing the cost of control

Every once in a while I play around with this idea for the design of a web language (server-side).

The nice thing about using first-class continuations to implement a web library is that you can write your code in direct style, but a big down-side is that you still have to figure out how to manage the storage of those continuations. But the alternative of essentially representing the control with program data structures, i.e. with explicit representations of the state of the computation, is really painful.

So I've thought of taking a page from Haskell's playbook: what if you separated a web language into two portions? One language would be for writing the "driver" of the program, where you can call send/suspend and computations may be suspended and restarted an arbitrary number of times. The other language would be "pure" (well, let's say full Scheme, but no send/suspend). In other words, replace Haskell's IO monad with the Web monad. As with Haskell, code in the Web monad can call pure code, but not vice versa.

The benefit of this would be that you could still write in direct style, but you've made explicit the portions of the program where control will cost you. Then you could play with different ways of managing that cost--expiration of continuations, back-off for expiration, etc.--by playing with the design of the Web monad, which wouldn't affect the pure language.


Ryan Culpepper said...

If I had to pick just one feature for a high-level web programming language, it would be the ability to turn closures into URLs. The problem I've had with send/suspend is that my web pages frequently have multiple nontrivial continuations, and send/suspend returns a web interaction record that you then have to pick apart. It's useful sometimes, but it's just the wrong primitive.

You could play the state monad game with that feature too, but the state monad is less satisfying than the continuation monad, I think. Or is it the writer monad?

Jay McCarthy said...

I'd say that this is a pretty good summary of what WASH actually IS, although there is not a huge amount of experimentation with different implementations of the Web monads.

In PLT world, you have two major customization points: When using implementation-level continuations, you can control how their hash table is managed. When using the continuation-removal transformation, you can store, represent, and manipulate the continuations in any way. (For example, you might want to sign them and then send them to the client... or you might want to SHA1 them, store them on disk, and send the SHA1 to the client, etc.)


Ryan, your feature request IS send/suspend/dispatch. The only subtlety is that you can't just turn a closure into a URL, you also need to specify where the closure will return TO after it's been called. That is specified as the calling context to s/s/d.

Notice that the interesting thing about s/s/d is that the lexical context of the closure is preserved... if you just want to bind some random procedure (that isn't capturing a lexical context), then a dispatch table a la Perl works just fine.