MonadBaseControl: how to remove simpleHTTP from Happstack?
How to use MonadBaseControl
from monad-control to bring up simpleHTTP
defined in happstack-server ?
Current type simpleHTTP
:
simpleHTTP :: ToMessage a
=> Conf -> ServerPartT IO a -> IO ()
Expected type simpleHTTPLifted
:
simpleHTTPLifted :: (MonadBaseControl IO m, ToMessage a)
=> Conf -> ServerPartT m a -> m ()
My current attempt (does not compile):
simpleHTTPLifted conf action =
liftBaseWith (\runInBase ->
let
fixTypes :: UnWebT m a -> UnWebT IO a
fixTypes c = runInBase c
in simpleHTTP conf (mapServerPartT fixTypes action)
)
Please note that a similar puzzle in my linked question: MonadBaseControl: how to remove a ThreadGroup
I would like to understand how to raise such functions in general and what are the usual steps taken when presenting such a puzzle?
EDIT: I think I need a function like (StM m a -> a)
. restoreM
pretty close, but doesn't. I also found an ugly version fixTypes
:
fixTypes :: UnWebT m a -> UnWebT IO a
fixTypes c = do
x <- newIORef undefined
_ <- runInBase (c >>= liftBase . writeIORef x)
readIORef x
It depends on IO being the underlying monad, which is not the optimal solution.
source to share
I don't think you can film this at all for anyone MonadBaseControl IO m
. There are some m
we can do.
Generally
UnWebT m
is isomorphic WebT m
, which has MonadTransControl
. You can convert to WebT
and WebT
using mkWebT :: UnWebT m a -> WebT m a
and ununWebT :: WebT m a -> UnWebT m a
.
MonadBaseControl
is a fancy wrapper around the transformer stack MonadTransControl
that flattens the stack so that the startup and recovery state happens all the way down the stack and restores it completely again. You can understand MonadBaseControl
by understanding MonadTransControl
, which I will briefly repeat here:
class MonadTrans t => MonadTransControl t where
data StT t :: * -> *
liftWith :: Monad m => (Run t -> m a) -> t m a
restoreT :: Monad m => m (StT t a) -> t m a
type Run t = forall n b. Monad n => t n b -> n (StT t b)
The class speaks with liftWith
. "I have provided a temporary launch t m
in m
which you can use to create actions in m
which I will in turn launch." The result type StT
says, "The results of t m
things I'm running in m
because you won't be available at all t m
; I need to save my state somewhere, and you have to give me a chance to restore my state if you want results."
Another way of saying roughly the same is, "I can temporarily deploy the base monad." The implementation question fixTypes
boils down to "Given that we can temporarily deploy a WebT
from m
and can temporarily deploy m
from IO
, can we permanently deploy m
from IO
?" for which the answer prohibiting possibility IO
is almost certainly "no."
IO Tricks
I suspect there m
is such a thing that "ugly" fixTypes
will do terrible things like never call writeIORef
and thus return undefined
or execute code asynchronously and therefore call writeIORef
after readIORef
, I'm not sure. This is complicated by the consideration that the action created liftBaseWith
is never used in such degenerate cases.
For Comonads
There must be a way to raise simpleHttp
without trickery IO
exactly when the state of the monad m
is Comonad
and therefore has a function extract :: StM m a -> a
. For example, this would be the case StateT s m
that essentially has StM s a ~ (s, a)
.
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Happstack.Server.SimpleHTTP
import Control.Comonad
import Control.Monad.Base
import Control.Monad.Trans.Control
simpleHTTPLifted :: forall m a. (MonadBaseControl IO m, Comonad (StM m), ToMessage a)
=> Conf -> ServerPartT m a -> m ()
simpleHTTPLifted conf action =
liftBaseWith (\runInBase ->
let
fixTypes :: UnWebT m b -> UnWebT IO b
fixTypes = fmap extract . runInBase
in simpleHTTP conf (mapServerPartT fixTypes action)
)
In practice, this is not very useful because newtype
, as defined in older versions of monad-control, there is no instance Comonad
, and type synonyms in newer versions of monad-control make no effort to make the result as an argument of the latter type. For example, the newest version of monad-control type StT (StateT s) a = (a, s)
.
source to share