Thanks again for starting the discussion!
As I mentioned, for Servant I think it's unlikely we'd completely move away from our current handlers, since we don't want to lose all the type information we have, and don't want to impose such information on others. So I'm hoping the next best thing might be achievable - allowing the new-style handlers to be run directly, and having conversion functions from our current handlers to the new style. I think the first is easy, and the second possible. Since there isn't enough information at the value-level to establish where it is our handlers are getting their arguments from (query string, headers, request body, etc.), we'd need a Proxy argument for the relevant part of the api. Something like:
convert :: (CanConvert api x) => Proxy api -> x -> NewHanderM ()
Where 'convert' would need to walk down the arguments of x and pull arguments from the appropriate places. E.g., if
x ~ Int -> Person -> ExceptT ServantErr IO (), and
api ~ Header "H" Int :> ReqBody '[JSON] Person -> Post '[] ()
we'd have 'convert' conceptually doing: convertExceptT $ liftM2 x (parseHeader <$> getHeader "H") (decode <$> getBody), where getHeader and getBody are functions in the new handler monad (/class). (This isn't quite right, since decoding failures need to be handled).
Though as I mentioned before, since for servant at least in one direction it'd be a conversion rather than direct usage of the new handler, and since we can already convert any servant handler plus appropriate Proxy into an Application, and can use any Application as a handler, for us it'd be a lot easier to just use Application. As far as I can tell, this is also true in a couple of other frameworks. Indeed, one of the great things about the Application signature, in my opinion, is that it works well both as the signature for an entire Application and for a handler (that gets a modified request). The only problem we've come across with that idea is that the type of failure of the handler is opaque to the outer framework - so e.g., there's no easy way to tell whether re-routing needs to be triggered because the handler failed to match. This, however, would still be a problem in the model mentioned above. Having something like Application, but with return type IO (Either ReroutePlz ResponseReceived), would likely suffice (as would settling on an exception type).