Hi Toralf,
I'll give this its proper attention soon but for now I'm just going to
forward your message to the snap list.
G
--
Gregory Collins <gr...@gregorycollins.net>
Hi Toralf,I hope you'll forgive me for the egregious delay in getting back to you on this.
Just based on having a quick look at your email, I think that you've identified a problem where our API could do a better job of expressing an idiom. About your proposed combinator set; is there a reason you preferred "... -> m Bool" to the MonadPlus/Alternative semantics? I think a lot of the things you were trying to do with the gist you posted can be expressed in those terms. For instance:
when :: MonadSnap m => m Bool -> m a -> m awhen p m = p >>= resultwhereresult True = mresult False = getResponse >>= finishWithCan be written aswhen :: MonadSnap m => m Bool -> m a -> m awhen p m = (p >>= guard >> m) <|> (getResponse >>= finishWith)
Your example about "method" can also be expressed in these terms:methodOr405 :: MonadSnap m => Method -> m a -> m amethodOr405 m act = method m act <|> serve405where-- do other stuff hereserve405 = finishWith $ setResponseCode 405 $ emptyResponse
I'd encourage you to see how many of the things in the gist you posted can be written this way. We don't always specify concrete behaviour for things like returning 405 for method calls, because we don't always want to be too tied into things which could be considered policy decisions. Stipulating that method calls a finishWith also precludes constructs like "method GET a <|> method POST b".
That said, there are probably convenient guards we're missing, like:guardParam :: MonadSnap m => ByteString -> (ByteString -> Bool) -> m ()guardParam k p = getParam k >>= maybe pass (guard . p)
withParam :: MonadSnap m => ByteString -> (ByteString -> m a) -> m awithParam k m = getParam k >>= maybe pass mguardHeader :: MonadSnap m => CI ByteString -> (ByteString -> Bool) -> m ()guardHeader h p = getsRequest (getHeader h) >>= maybe pass (guard . p)
withHeader :: MonadSnap m => CI ByteString -> (ByteString -> m a) -> m awithHeader h m = getsRequest (getHeader h) >>= maybe pass mwithCookie :: MonadSnap m => ByteString -> (Cookie -> m a) -> m awithCookie c m = getCookie c >>= maybe pass mWhat do you think?