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.

+3


source to share


1 answer


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)

.

+1


source







All Articles