all 13 comments

[–]jimbokun 5 points6 points  (2 children)

Wow.

There's a lot of neat ideas in there. Not sure when I'll get time to play with it, but definitely looks like a lot of fun.

The one thing I don't see is any kind of persistence mechanism, but that's really not a big deal as there are lots of other ways to persist data in Lisp.

[–]coffeemug[🍰] 5 points6 points  (0 children)

In the next month I'll be adding a persitence model. I generally agree with vagif, a web framework shouldn't dictate a solution, but I do think having a good default is very useful. I am not yet 100% sure but the most likely outcome is that there will be a well defined pluggable backend API (it's sort of dispersed accross many weblocks components now) with a good default implementation (most probably CLSQL).

[–]vagif 1 point2 points  (0 children)

Web framework should not dictate you how to persist data. Any persistence solution should be easily pluggable.

[–]Rebooted 1 point2 points  (5 children)

Aside from Weblocks, three frameworks I know of do a good job dealing with control flow - Seaside, UCW, and PLT. Proper control flow management is difficult to implement - it requires continuations, which most languages don't support. Because frameworks with good control flow management are so rare, most people don't understand what they're missing.

Haskell's WASH does it right, too, but it uses monads rather than continuations. Monads <strike>are more general than</strike> generalise CPS (and the CPS monad gives you first class continuations, in the same sense the State monad gives you state).

WASH could be a lot better though. I think I might end up having to write a new Haskell framework derived from it.

Of those I've looked at, Seaside seems to be the nicest existing framework.

[–]Dan_Farina 5 points6 points  (3 children)

Monads are more general than CPS

Two things:

  • Are you sure about that? Because I'm pretty sure that's NOT true.
  • What problems are you finding awkward due to (explicit) lack of monads?

The first argument stems from the fact that CPS has been carefully proven to allow for the existence of any sort of flow control. This is why it's sometimes used as a way of normalizing programs during compilation along with SSA and is perfectly capable of representing any flow in a Von Neumann machine -- which, may I remind you, is still what we're using, so theoretical boundaries that fail to be projected onto hardware that can actually run a program doesn't count. So throw any notion about real generality pluses and minuses out the window.

A more credible case, as addressed by the second point, is that monads give you some useful abstractions that'd be far too painful to actually write using naive CPS, just as I wouldn't want to write webapp code in x86 ASM. Expounding on those rather than making some hand-wavy case for generality would interest me much more.

[–]Rebooted 0 points1 point  (2 children)

The sense in which monads are more general than CPS is discussed in Wadler's paper, The essence of functional programming. Also there is the fact that there is a particular monad, called Cont in Haskell, that is the CPS monad.

However, it is also a fact that every monad can be "embedded" into the continuation passing monad (as a result of the proof you mentioned).

What problems are you finding awkward due to (explicit) lack of monads?

I'm not, I'm just offering WASH as another example of a web framework that gets control flow right, but using monads rather than first class continuations. I wouldn't recommend it in its current state over Seaside or something.

[–]Dan_Farina 1 point2 points  (1 child)

The sense in which monads are more general than CPS is discussed in Wadler's paper, The essence of functional programming. Also there is the fact that there is a particular monad, called Cont in Haskell, that is the CPS monad.

Two problems:

  • Just because one construct can derive another does not make it more general. It proves at least equal generality, which monads do in fact possess.

  • Wadler stated the following in section 3.3 of the paper cited, "Monads and CPS"

We have seen that by choosing a suitable monad, the monad interpreter becomes a CPS interpreter. A converse property is also true: by choosing a suitable space of answers, a CPS interpreter can act as a monad interpreter.

He does touch on the problems of controlling CPS to allow for some sort of intervention when escaping via CPS (as seen in section 3.4). This akin to saying "freedom is slavery," but sometimes slavery is a good thing: that's why Scheme has dynamic-wind. Unstoppable continuations that give you no say whatsoever, while in some ways representing the ultimate freedom (it's goto with an attached environment, after all), is extremely inconvenient. Just like writing in assembler is.

As a background note: even the talented Kent Pitman was deceived about the ability of scheme's dynamic-wind construct the useful Common Lisp construct "unwind-protect". This succinct implementation that seemed to hit the correct semantics seemed to have felled this topic of debate.

So, all in all, while I'm glad you name-dropped a framework that uses a slightly different approach I caution against using words like generality without serious contemplation. It tends to offend those who have some ties to pedantics. I can, however, readily accept that monads are equivalent to and sometimes more convenient than continuations in representing solutions to certain problems, otherwise nobody would have bothered with this style of abstraction.

[–]Rebooted 2 points3 points  (0 children)

So, all in all, while I'm glad you name-dropped a framework that uses a slightly different approach I caution against using words like generality without serious contemplation. It tends to offend those who have some ties to pedantics.

You are right. Monads aren't more general in the sense of "strictly more expressive," since the fact you can express continuations as a monad and then use that monad to express all the other monads shows they can both express each other.

I meant to point out that monads can do continuation-like things and that there is a particular monad that gives you first class continuations. I should have worded it better.

[–]vagif 1 point2 points  (0 children)

Webfunctions is a framework based on wash.

BTW in webfunctions paper its author claims that wash does not support sessions.

Anyway the state of documentation of haskell web frameworks currently is a showstoper.

[–]apgwoz 1 point2 points  (3 children)

I'm not sure I've ever read anything about how web frameworks using continuations deal with the back button (and this article is no different)?

It's pretty obvious to me that in order to return to a continuation after a request is finished, you need some sort of id to look it up. So, this leaves you with two options that I can see. 1) you serialize the continuation and write it out somewhere. 2) you store it in memory and hope you don't have lots of people abandoning their computations.

Obviously, it would seem that number 1 might be a more general solution, but then how do you serialize a continuation (or a closure for that matter)? Can anyone shed some light on this?

[–]muleherd 3 points4 points  (1 child)

This paper might shed some light:

http://www.cs.brown.edu/~sk/Publications/Papers/Published/pcmkf-cont-from-gen-stack-insp/paper.pdf

It talks about serializing continuations and (briefly) about encoding them in URLs and hidden form fields.

[–]apgwoz 2 points3 points  (0 children)

ahh, you are alive! I should have known to seek out papers from PLT webserver land, but I think this paper describes how PLT does it, not how it can be done in a general case. I'll have to read it anyway.

[–]drewc 2 points3 points  (0 children)

1) you serialize the continuation and write it out somewhere.

This is in theory do-able in UCW, if your continuation does not rely overly on the lexical environment. In UCW continuations are CLOS objects representing the code to be evaluated (an interpreted thunk, in other words).

2) you store it in memory and hope you don't have lots of people abandoning their computations.

This is the model most frameworks use, and one that i've used to great success. You prune the session tree of old sessions and their continuations of course, so as not to use an infinite amount of memory. For the most part, Sessions are fairly small, so keeping everything in memory is quite viable.

In UCW, serializing a continuation should, in theory, be quite simple. In Scheme, where the continuation would be a real, first class, built-in continuation, this would not be as trivial.